From 435f147b180978f52fbd8c0ef2d5b681249ed194 Mon Sep 17 00:00:00 2001 From: Sunny Shah Date: Fri, 22 Jul 2016 15:55:08 -0500 Subject: [PATCH 001/180] The include "libtasn1.h" was wrongly added and shouldn't be there, removed it with this commit --- dataflowAPI/rose/semantics/SymEvalSemantics.C | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dataflowAPI/rose/semantics/SymEvalSemantics.C b/dataflowAPI/rose/semantics/SymEvalSemantics.C index 9e453dac60..043c64895c 100644 --- a/dataflowAPI/rose/semantics/SymEvalSemantics.C +++ b/dataflowAPI/rose/semantics/SymEvalSemantics.C @@ -2,7 +2,6 @@ // Created by ssunny on 7/1/16. // -#include #include "SymEvalSemantics.h" using namespace rose::BinaryAnalysis::InstructionSemantics2; @@ -287,4 +286,4 @@ void SymEvalSemantics::RiscOperatorsARM64::writeMemory(const RegisterDescriptor const BaseSemantics::SValuePtr &data, const BaseSemantics::SValuePtr &/*cond*/) { currentState()->writeMemory(addr, data, this, this); -} \ No newline at end of file +} From ad9fb33a42d23725d5e5e4ca3de73a2c26fbe033 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 21 Jul 2016 17:44:40 -0400 Subject: [PATCH 002/180] Fix std::isnan compile error G++ 5.4 needs the using directive in c++11 mode. --- dataflowAPI/rose/rangemap.C | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dataflowAPI/rose/rangemap.C b/dataflowAPI/rose/rangemap.C index 3faadecb0f..85bf526b98 100644 --- a/dataflowAPI/rose/rangemap.C +++ b/dataflowAPI/rose/rangemap.C @@ -6,10 +6,8 @@ #define isnan(x) _isnan(x) #define INFINITY (DBL_MAX+DBL_MAX) #define NAN (INFINITY-INFINITY) -#elif __cplusplus >= 201103L - // isnan is already defined in this scope #else - using std::isnan; + #define isnan(x) std::isnan(x) #endif /****************************************************************************************************************************** From aadc64551ed919e1093e86c38cb86e938470a1a1 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 21 Jul 2016 18:53:44 -0400 Subject: [PATCH 003/180] only suppress warnings for rose Signed-off-by: Peter Foley --- parseAPI/CMakeLists.txt | 74 +++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/parseAPI/CMakeLists.txt b/parseAPI/CMakeLists.txt index e0de2bbd41..665f070a28 100644 --- a/parseAPI/CMakeLists.txt +++ b/parseAPI/CMakeLists.txt @@ -38,6 +38,9 @@ set (SRC_LIST src/LoopTreeNode.C src/IdiomModelDesc.C src/ProbabilisticParser.C + ) + +set(ROSE_SRC ../dataflowAPI/src/ABI.C ../dataflowAPI/src/Absloc.C ../dataflowAPI/src/AbslocInterface.C @@ -47,38 +50,44 @@ set (SRC_LIST ../dataflowAPI/src/InstructionCache.C ../dataflowAPI/src/liveness.C ../dataflowAPI/src/RegisterMap.C - ../dataflowAPI/src/RoseImpl.C - ../dataflowAPI/rose/ExtentMap.C - ../dataflowAPI/rose/rangemap.C - ../dataflowAPI/rose/util/Assert.C - ../dataflowAPI/rose/util/Message.C - ../dataflowAPI/rose/util/Sawyer.C - ../dataflowAPI/rose/util/Synchronization.C - ../dataflowAPI/rose/util/rose_getline.C - ../dataflowAPI/rose/util/SmallObject.C - ../dataflowAPI/rose/util/Stopwatch.C - ../dataflowAPI/rose/util/StringUtility.C - ../dataflowAPI/rose/util/Attribute.C - ../dataflowAPI/rose/util/Combinatorics.C - ../dataflowAPI/rose/util/LinearCongruentialGenerator.C - ../dataflowAPI/rose/semantics/BaseSemantics2.C - #../dataflowAPI/rose/semantics/ConcreteSemantics2.C - ../dataflowAPI/rose/semantics/DispatcherARM64.C - ../dataflowAPI/rose/semantics/RegisterParts.C - ../dataflowAPI/rose/semantics/Registers.C - ../dataflowAPI/rose/semantics/SMTSolver.C - ../dataflowAPI/rose/semantics/BinarySymbolicExpr.C - ../dataflowAPI/rose/semantics/RegisterStateGeneric.C - ../dataflowAPI/rose/semantics/SymEvalSemantics.C - ../dataflowAPI/src/RoseInsnFactory.C - ../dataflowAPI/src/slicing.C - ../dataflowAPI/src/stackanalysis.C - ../dataflowAPI/src/SymbolicExpansion.C - ../dataflowAPI/src/SymEval.C - ../dataflowAPI/src/SymEvalPolicy.C - ../dataflowAPI/src/templates.C - ../dataflowAPI/src/Visitors.C - ) + ../dataflowAPI/src/RoseImpl.C + ../dataflowAPI/src/RoseInsnFactory.C + ../dataflowAPI/src/slicing.C + ../dataflowAPI/src/stackanalysis.C + ../dataflowAPI/src/SymbolicExpansion.C + ../dataflowAPI/src/SymEval.C + ../dataflowAPI/src/SymEvalPolicy.C + ../dataflowAPI/src/templates.C + ../dataflowAPI/src/Visitors.C + ../dataflowAPI/rose/ExtentMap.C + ../dataflowAPI/rose/rangemap.C + ../dataflowAPI/rose/util/Assert.C + ../dataflowAPI/rose/util/Message.C + ../dataflowAPI/rose/util/Sawyer.C + ../dataflowAPI/rose/util/Synchronization.C + ../dataflowAPI/rose/util/rose_getline.C + ../dataflowAPI/rose/util/SmallObject.C + ../dataflowAPI/rose/util/Stopwatch.C + ../dataflowAPI/rose/util/StringUtility.C + ../dataflowAPI/rose/util/Attribute.C + ../dataflowAPI/rose/util/Combinatorics.C + ../dataflowAPI/rose/util/LinearCongruentialGenerator.C + ../dataflowAPI/rose/semantics/BaseSemantics2.C + #../dataflowAPI/rose/semantics/ConcreteSemantics2.C + ../dataflowAPI/rose/semantics/DispatcherARM64.C + ../dataflowAPI/rose/semantics/RegisterParts.C + ../dataflowAPI/rose/semantics/Registers.C + #../dataflowAPI/rose/semantics/SMTSolver.C + ../dataflowAPI/rose/semantics/BinarySymbolicExpr.C + ../dataflowAPI/rose/semantics/RegisterStateGeneric.C + ../dataflowAPI/rose/semantics/SymEvalSemantics.C +) + +# FIXME: Rose needs a bunch of warning cleanup +SET_SOURCE_FILES_PROPERTIES(${ROSE_SRC} PROPERTIES LANGUAGE CXX COMPILE_FLAGS -w) +set (SRC_LIST ${SRC_LIST} + ${ROSE_SRC} +) if (LIGHTWEIGHT_SYMTAB) set (SRC_LIST ${SRC_LIST} @@ -114,7 +123,6 @@ set (SRC_LIST ${SRC_LIST} ) endif() -SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX COMPILE_FLAGS -w) ADD_DEFINITIONS(-DPARSER_LIB) ADD_DEFINITIONS(-DDATAFLOW_LIB) From 8d5a53c9fd84600bdf1d291e2a182b29bbe9d109 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 21 Jul 2016 18:55:34 -0400 Subject: [PATCH 004/180] make Rose build on windows --- dataflowAPI/rose/util/LinearCongruentialGenerator.C | 2 +- dataflowAPI/rose/util/StringUtility.C | 5 +++-- dataflowAPI/rose/util/StringUtility.h | 2 +- external/inttypes-win.h | 6 ++++++ external/stdint-win.h | 6 ++++++ parseAPI/CMakeLists.txt | 7 +++++++ 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/dataflowAPI/rose/util/LinearCongruentialGenerator.C b/dataflowAPI/rose/util/LinearCongruentialGenerator.C index 70ad85f509..dfd4ec80a9 100644 --- a/dataflowAPI/rose/util/LinearCongruentialGenerator.C +++ b/dataflowAPI/rose/util/LinearCongruentialGenerator.C @@ -12,7 +12,7 @@ #include #else -#include "timing.h" +#include "common/src/timing.h" #endif #ifndef _MSC_VER diff --git a/dataflowAPI/rose/util/StringUtility.C b/dataflowAPI/rose/util/StringUtility.C index fcf4e599a9..85e82a780d 100644 --- a/dataflowAPI/rose/util/StringUtility.C +++ b/dataflowAPI/rose/util/StringUtility.C @@ -58,9 +58,10 @@ // tps (11/10/2009): This include is needed in windows to find the realpath #if ROSE_MICROSOFT_OS -#include -// DQ (11/27/2009): this is required for use of GetFullPathName() (below). #include +// DQ (11/27/2009): this is required for use of GetFullPathName() (below). +#else +#include #endif // DQ (12/31/2005): This is allowed in C files where it can not // effect the users applcation (just not in header files). diff --git a/dataflowAPI/rose/util/StringUtility.h b/dataflowAPI/rose/util/StringUtility.h index 9ec819261e..23e81ddd57 100644 --- a/dataflowAPI/rose/util/StringUtility.h +++ b/dataflowAPI/rose/util/StringUtility.h @@ -14,7 +14,7 @@ #if ROSE_MICROSOFT_OS // This is the boost solution for lack of support for stdint.h (e.g. types such as "uint64_t") -#include +#include "external/stdint-win.h" #endif /** Functions for operating on strings. diff --git a/external/inttypes-win.h b/external/inttypes-win.h index c2df8b3e1d..cd530cf719 100644 --- a/external/inttypes-win.h +++ b/external/inttypes-win.h @@ -33,6 +33,12 @@ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] +// Modern Visual Studio has sane inttypes.h +#if _MSC_VER >= 1900 +#include +#define _MSC_INTTYPES_H_ +#endif + #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ diff --git a/external/stdint-win.h b/external/stdint-win.h index ffc9a3c7f5..33dfd0691b 100644 --- a/external/stdint-win.h +++ b/external/stdint-win.h @@ -33,6 +33,12 @@ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] +// Modern Visual Studio has sane stdint.h +#if _MSC_VER >= 1900 +#include +#define _MSC_STDINT_H_ +#endif + #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ diff --git a/parseAPI/CMakeLists.txt b/parseAPI/CMakeLists.txt index 665f070a28..cb314d25dd 100644 --- a/parseAPI/CMakeLists.txt +++ b/parseAPI/CMakeLists.txt @@ -127,11 +127,18 @@ endif() ADD_DEFINITIONS(-DPARSER_LIB) ADD_DEFINITIONS(-DDATAFLOW_LIB) +if(WIN32) +ADD_DEFINITIONS(-DROSE_UTIL_EXPORTS) +ADD_DEFINITIONS(-DNOMINMAX) +endif() + dyninst_library(parseAPI common instructionAPI ${SYMREADER}) if (UNIX) # Boost auto-links on Windows; don't double-link target_link_private_libraries(parseAPI ${Boost_LIBRARIES}) +elseif(WIN32) +target_link_private_libraries(parseAPI shlwapi) endif() FILE (GLOB headers "h/*.h") From 1b929295c3e9083996d799e2ad5bc8e5f0075914 Mon Sep 17 00:00:00 2001 From: John Detter Date: Fri, 22 Jul 2016 16:39:03 -0500 Subject: [PATCH 005/180] Started work on dataflowAPI based analysis for findMain --- dyninstAPI/src/image.C | 428 ++++++++++++++++++++++++----------------- 1 file changed, 256 insertions(+), 172 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index 9153f90645..d36d4d8098 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -58,6 +58,8 @@ #include "parseAPI/h/CodeObject.h" #include "parseAPI/h/CFG.h" +#include "dataflowAPI/h/AbslocInterface.h" + #if defined(TIMED_PARSE) #include #endif @@ -409,21 +411,21 @@ void image::findMain() // (Some strange DSOs also have INTERP, but this is rare.) if(!desc_.isSharedObject() || linkedFile->getInterpreterName() != NULL) { - bool foundMain = false; - bool foundStart = false; - bool foundFini = false; - //check if 'main' is in allsymbols + bool foundMain = false; + bool foundStart = false; + bool foundFini = false; + //check if 'main' is in allsymbols vector funcs; if (linkedFile->findFunctionsByName(funcs, "main") || - linkedFile->findFunctionsByName(funcs, "_main")) + linkedFile->findFunctionsByName(funcs, "_main")) foundMain = true; else if (linkedFile->findFunctionsByName(funcs, "_start")) foundStart = true; else if (linkedFile->findFunctionsByName(funcs, "_fini")) foundFini = true; - - Region *eReg = NULL; - bool foundText = linkedFile->findRegion(eReg, ".text"); + + Region *eReg = NULL; + bool foundText = linkedFile->findRegion(eReg, ".text"); if (foundText == false) { return; } @@ -435,8 +437,8 @@ void image::findMain() Address eAddr = linkedFile->getEntryOffset(); eAddr = deref_opd(linkedFile, eAddr); - bool parseInAllLoadableRegions = (BPatch_normalMode != mode_); - SymtabCodeSource scs(linkedFile, filt, parseInAllLoadableRegions); + bool parseInAllLoadableRegions = (BPatch_normalMode != mode_); + SymtabCodeSource scs(linkedFile, filt, parseInAllLoadableRegions); CodeObject tco(&scs,NULL,NULL,false); tco.parse(eAddr,false); @@ -465,8 +467,8 @@ void image::findMain() b = (*cit)->src(); } else { startup_printf("%s[%d] _start has unexpected number (%d) of" - " call edges, bailing on findMain()\n", - FILE__,__LINE__,calls.size()); + " call edges, bailing on findMain()\n", + FILE__,__LINE__,calls.size()); return; } if (!b) return; @@ -479,37 +481,37 @@ void image::findMain() return; } else { startup_printf("%s[%d] found main at %lx\n", - FILE__,__LINE__,mainAddress); + FILE__,__LINE__,mainAddress); } - Symbol *newSym= new Symbol( "main", - Symbol::ST_FUNCTION, - Symbol::SL_LOCAL, - Symbol::SV_INTERNAL, - mainAddress, - linkedFile->getDefaultModule(), - eReg, - 0 ); - linkedFile->addSymbol(newSym); + Symbol *newSym= new Symbol( "main", + Symbol::ST_FUNCTION, + Symbol::SL_LOCAL, + Symbol::SV_INTERNAL, + mainAddress, + linkedFile->getDefaultModule(), + eReg, + 0 ); + linkedFile->addSymbol(newSym); } } #elif defined(i386_unknown_linux2_0) \ -|| defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \ -|| (defined(os_freebsd) \ - && (defined(arch_x86) || defined(arch_x86_64))) + || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \ + || (defined(os_freebsd) \ + && (defined(arch_x86) || defined(arch_x86_64))) // Only look for main in executables, but do allow position-independent // executables (PIE) which look like shared objects with an INTERP. // (Some strange DSOs also have INTERP, but this is rare.) if(!desc_.isSharedObject() || linkedFile->getInterpreterName() != NULL) { - bool foundMain = false; - bool foundStart = false; - bool foundFini = false; + bool foundMain = false; + bool foundStart = false; + bool foundFini = false; - //check if 'main' is in allsymbols + //check if 'main' is in allsymbols vector funcs; if (linkedFile->findFunctionsByName(funcs, "main") || - linkedFile->findFunctionsByName(funcs, "_main")) { - foundMain = true; + linkedFile->findFunctionsByName(funcs, "_main")) { + foundMain = true; } if (linkedFile->findFunctionsByName(funcs, "_start")) { @@ -523,68 +525,150 @@ void image::findMain() Address eAddr = linkedFile->getEntryOffset(); Region *eReg = linkedFile->findEnclosingRegion(eAddr); if (!eReg) { - return; + return; } Address eStart = eReg->getMemOffset(); - if( !foundMain ) - { + if( !foundMain ) + { logLine( "No main symbol found: creating symbol for main\n" ); - //find and add main to allsymbols + //find and add main to allsymbols const unsigned char* p; - + p = (( const unsigned char * ) eReg->getPtrToRawData()); if (eAddr > eStart) { - p += (eAddr - eStart); + p += (eAddr - eStart); } + bool mode_64 = false; switch(linkedFile->getAddressWidth()) { - case 4: - // 32-bit... + case 4: + // 32-bit... startup_printf("%s[%u]: setting 32-bit mode\n", - FILE__,__LINE__); - ia32_set_mode_64(false); + FILE__,__LINE__); + ia32_set_mode_64(false); break; - case 8: + case 8: + mode_64 = true; startup_printf("%s[%u]: setting 64-bit mode\n", - FILE__,__LINE__); - ia32_set_mode_64(true); - break; - default: - assert(0 && "Illegal address width"); - break; + FILE__,__LINE__); + ia32_set_mode_64(true); + break; + default: + assert(0 && "Illegal address width"); + break; } - instruction insn; - insn.setInstruction( p ); + // instruction insn; + // insn.setInstruction( p ); Address mainAddress = 0; + cout << "Guess main:" << endl; - // Create a temporary SymtabCodeSource that we can use for parsing. - // We're going to throw it away when we're done so that we can re-sync - // with the new symbols we're going to add shortly. - bool parseInAllLoadableRegions = (BPatch_normalMode != mode_); - SymtabCodeSource scs(linkedFile, filt, parseInAllLoadableRegions); + // Create a temporary SymtabCodeSource that we can use for parsing. + // We're going to throw it away when we're done so that we can re-sync + // with the new symbols we're going to add shortly. + bool parseInAllLoadableRegions = (BPatch_normalMode != mode_); + SymtabCodeSource scs(linkedFile, filt, parseInAllLoadableRegions); + CodeObject co(&scs); #if !defined(os_freebsd) - const unsigned char *lastP = 0; - while( !insn.isCall() ) + + Address entry_point = (Address)linkedFile->getEntryOffset(); + + /* Get the code regions we are looking at */ + std::set regions; + scs.findRegions(entry_point, regions); + cout << "\t" << regions.size() << " regions were found" << endl; + + /* We should only get one region */ + if(regions.size() != 1) + assert(!"Overlapping or non existant regions!"); + CodeRegion* region = *regions.begin(); + assert(region); + + /* Parse the function we're looking at */ + co.parse(region, entry_point, true); + cout << "\tParsing the region..." << endl; + + /* Get the parsed Function */ + vector funcs; + Function* func = co.findFuncByEntry(region, entry_point); + assert(func); /* This should really exist now */ + cout << "\tGot function " << func->name() << endl; + + /* Use dataflow analysis here to determine the value of EDI */ + const unsigned char* raw = p; + instruction insn; + insn.setInstruction(raw); + Address insn_addr = entry_point; + cout << "\tStarting address: " << insn_addr << endl; + cout << "\tInstructions:" << endl; + + const unsigned char *last_insn = NULL; + while(!insn.isCall()) { - lastP = p; - p += insn.size(); - insn.setInstruction( p ); + last_insn = raw; + raw += insn.size(); + insn.setInstruction(raw); } + if(!last_insn) /* We cannot do analysis on this */ + { + assert(!"findMain analysis has failed"); + return; + } + + /* Calculate the address of the instruction */ + insn_addr += last_insn - p; + cout << "\tAddr difference: " << (last_insn - p) << endl; + cout << "\tFinal address: " << insn_addr << endl; + + /* Decode the instruction */ + InstructionAPI::InstructionDecoder* decoder = NULL; + if(mode_64) + { + decoder = new InstructionAPI::InstructionDecoder( + last_insn, insn.size(), Dyninst::Arch_x86_64); + } else { + decoder = new InstructionAPI::InstructionDecoder( + last_insn, insn.size(), Dyninst::Arch_x86); + } + InstructionAPI::Instruction::Ptr insn_ptr = decoder->decode(last_insn); + + /* Get the block for this instruction */ + assert(region->contains(insn_addr)); + std::set blocks; + co.findBlocks(region, insn_addr, blocks); + assert(blocks.size() == 1); + Block* b = *blocks.begin(); + assert(b); + + /* Let's get the assignment for this instruction. */ + std::vector assignments; + Dyninst::AssignmentConverter assign_convert(true, true); + assign_convert.convert(insn_ptr, insn_addr, func, b, assignments); + cout << "\t" << assignments.size() << " assignments were returned." << endl; + + + + // while( !insn.isCall() ) + // { + // lastP = p; + // p += insn.size(); + // insn.setInstruction( p ); + // } + // We _really_ can't handle a call with nothing before it.... - assert(lastP); + // assert(lastP); // FIXME: this assumes that the instruction immediately before the call sets // the main address - this may not be true. - instruction preCall; - preCall.setInstruction(lastP); + // instruction preCall; + // preCall.setInstruction(lastP); - mainAddress = get_immediate_operand(&preCall); + // mainAddress = get_immediate_operand(&preCall); #else // Heuristic: main is the target of the 4th call in the text section using namespace Dyninst::InstructionAPI; @@ -594,7 +678,7 @@ void image::findMain() Instruction::Ptr curInsn = decoder.decode(); while( numCalls < 4 && curInsn && curInsn->isValid() && - bytesSeen < eReg->getMemSize()) + bytesSeen < eReg->getMemSize()) { InsnCategory category = curInsn->getCategory(); if( category == c_CallInsn ) { @@ -627,10 +711,10 @@ void image::findMain() if(!mainAddress || !scs.isValidAddress(mainAddress)) { startup_printf("%s[%u]: invalid main address 0x%lx\n", - FILE__, __LINE__, mainAddress); + FILE__, __LINE__, mainAddress); } else { startup_printf("%s[%u]: set main address to 0x%lx\n", - FILE__,__LINE__,mainAddress); + FILE__,__LINE__,mainAddress); } /* Note: creating a symbol for main at the invalid address @@ -641,64 +725,64 @@ void image::findMain() findMain, like all important utility functions, should have a way of gracefully indicating that it has failed. It should not return void. NR - */ + */ - Region *pltsec; + Region *pltsec; if((linkedFile->findRegion(pltsec, ".plt")) && pltsec->isOffsetInRegion(mainAddress)) { - //logLine( "No static symbol for function main\n" ); + //logLine( "No static symbol for function main\n" ); Symbol *newSym = new Symbol("DYNINST_pltMain", - Symbol::ST_FUNCTION, - Symbol::SL_LOCAL, - Symbol::SV_INTERNAL, - mainAddress, - linkedFile->getDefaultModule(), - eReg, - 0 ); + Symbol::ST_FUNCTION, + Symbol::SL_LOCAL, + Symbol::SV_INTERNAL, + mainAddress, + linkedFile->getDefaultModule(), + eReg, + 0 ); linkedFile->addSymbol( newSym ); - } - else - { - Symbol *newSym= new Symbol( "main", - Symbol::ST_FUNCTION, - Symbol::SL_LOCAL, - Symbol::SV_INTERNAL, - mainAddress, - linkedFile->getDefaultModule(), - eReg, - 0 ); - linkedFile->addSymbol(newSym); + } + else + { + Symbol *newSym= new Symbol( "main", + Symbol::ST_FUNCTION, + Symbol::SL_LOCAL, + Symbol::SV_INTERNAL, + mainAddress, + linkedFile->getDefaultModule(), + eReg, + 0 ); + linkedFile->addSymbol(newSym); } } - if( !foundStart ) - { + if( !foundStart ) + { Symbol *startSym = new Symbol( "_start", - Symbol::ST_FUNCTION, - Symbol::SL_LOCAL, - Symbol::SV_INTERNAL, - eReg->getMemOffset(), - linkedFile->getDefaultModule(), - eReg, - 0 ); + Symbol::ST_FUNCTION, + Symbol::SL_LOCAL, + Symbol::SV_INTERNAL, + eReg->getMemOffset(), + linkedFile->getDefaultModule(), + eReg, + 0 ); //cout << "sim for start!" << endl; - - linkedFile->addSymbol(startSym); - } - if( !foundFini ) - { - Region *finisec = NULL; - if (linkedFile->findRegion(finisec,".fini")) { - Symbol *finiSym = new Symbol( "_fini", - Symbol::ST_FUNCTION, - Symbol::SL_LOCAL, - Symbol::SV_INTERNAL, - finisec->getMemOffset(), - linkedFile->getDefaultModule(), - finisec, - 0 ); - linkedFile->addSymbol(finiSym); - } - } + + linkedFile->addSymbol(startSym); + } + if( !foundFini ) + { + Region *finisec = NULL; + if (linkedFile->findRegion(finisec,".fini")) { + Symbol *finiSym = new Symbol( "_fini", + Symbol::ST_FUNCTION, + Symbol::SL_LOCAL, + Symbol::SV_INTERNAL, + finisec->getMemOffset(), + linkedFile->getDefaultModule(), + finisec, + 0 ); + linkedFile->addSymbol(finiSym); + } + } } Region *dynamicsec; @@ -706,66 +790,66 @@ void image::findMain() if(linkedFile->findRegion(dynamicsec, ".dynamic")==true) { if(linkedFile->findSymbol(syms, - "_DYNAMIC", - Symbol::ST_UNKNOWN, - SymtabAPI::mangledName)==false) + "_DYNAMIC", + Symbol::ST_UNKNOWN, + SymtabAPI::mangledName)==false) { - Symbol *newSym = new Symbol( "_DYNAMIC", - Symbol::ST_OBJECT, - Symbol::SL_LOCAL, - Symbol::SV_INTERNAL, - dynamicsec->getMemOffset(), - linkedFile->getDefaultModule(), - dynamicsec, - 0 ); - linkedFile->addSymbol(newSym); - } + Symbol *newSym = new Symbol( "_DYNAMIC", + Symbol::ST_OBJECT, + Symbol::SL_LOCAL, + Symbol::SV_INTERNAL, + dynamicsec->getMemOffset(), + linkedFile->getDefaultModule(), + dynamicsec, + 0 ); + linkedFile->addSymbol(newSym); + } } - + #elif defined(i386_unknown_nt4_0) - if(linkedFile->isExec()) { - vector syms; - vector funcs; - Address eAddr = linkedFile->getEntryOffset(); - Region *eReg = linkedFile->findEnclosingRegion(eAddr); - - bool found_main = false; - for (unsigned i=0; ifindFunctionsByName(funcs, main_function_names[i])) { - found_main = true; - break; - } - } - if (found_main) { - if(!linkedFile->findSymbol(syms,"start",Symbol::ST_UNKNOWN, SymtabAPI::mangledName)) { - //use 'start' for mainCRTStartup. - Symbol *startSym = new Symbol( "start", - Symbol::ST_FUNCTION, - Symbol::SL_GLOBAL, - Symbol::SV_DEFAULT, - eAddr , - linkedFile->getDefaultModule(), - eReg, - UINT_MAX ); - linkedFile->addSymbol(startSym); - } - syms.clear(); - } - else { - // add entry point as main given that nothing else was found - startup_printf("[%s:%u] - findmain could not find symbol " - "for main, using binary entry point %x\n", - __FILE__, __LINE__, eAddr); - linkedFile->addSymbol(new Symbol("main", - Symbol::ST_FUNCTION, - Symbol::SL_GLOBAL, - Symbol::SV_DEFAULT, - eAddr, - linkedFile->getDefaultModule(), - eReg)); - } - } + if(linkedFile->isExec()) { + vector syms; + vector funcs; + Address eAddr = linkedFile->getEntryOffset(); + Region *eReg = linkedFile->findEnclosingRegion(eAddr); + + bool found_main = false; + for (unsigned i=0; ifindFunctionsByName(funcs, main_function_names[i])) { + found_main = true; + break; + } + } + if (found_main) { + if(!linkedFile->findSymbol(syms,"start",Symbol::ST_UNKNOWN, SymtabAPI::mangledName)) { + //use 'start' for mainCRTStartup. + Symbol *startSym = new Symbol( "start", + Symbol::ST_FUNCTION, + Symbol::SL_GLOBAL, + Symbol::SV_DEFAULT, + eAddr , + linkedFile->getDefaultModule(), + eReg, + UINT_MAX ); + linkedFile->addSymbol(startSym); + } + syms.clear(); + } + else { + // add entry point as main given that nothing else was found + startup_printf("[%s:%u] - findmain could not find symbol " + "for main, using binary entry point %x\n", + __FILE__, __LINE__, eAddr); + linkedFile->addSymbol(new Symbol("main", + Symbol::ST_FUNCTION, + Symbol::SL_GLOBAL, + Symbol::SV_DEFAULT, + eAddr, + linkedFile->getDefaultModule(), + eReg)); + } + } #endif } From 8c1d1794f74e52448b4f495ad5df82a8289b60e3 Mon Sep 17 00:00:00 2001 From: John Detter Date: Mon, 25 Jul 2016 15:25:59 -0500 Subject: [PATCH 006/180] test_pt_ls passing --- dyninstAPI/src/image.C | 114 ++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 29 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index d36d4d8098..1e0d5b214a 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -59,6 +59,7 @@ #include "parseAPI/h/CFG.h" #include "dataflowAPI/h/AbslocInterface.h" +#include "dataflowAPI/h/SymEval.h" #if defined(TIMED_PARSE) #include @@ -226,7 +227,7 @@ namespace { virtual ASTPtr visit(DataflowAPI::ConstantAST *c) {return c->ptr();}; virtual ASTPtr visit(DataflowAPI::VariableAST *v) {return v->ptr();}; - virtual AST::Ptr visit(DataflowAPI::RoseAST * r) { + virtual ASTPtr visit(DataflowAPI::RoseAST * r) { using namespace DataflowAPI; AST::Children newKids; @@ -396,6 +397,73 @@ namespace { } #endif +#include +#include +#include +#include +#include +#include + +class FindMainVisitor : public ASTVisitor +{ + using ASTVisitor::visit; + + public: + bool resolved; + Address target; + FindMainVisitor() : resolved(true), target(0){} + + virtual AST::Ptr visit(DataflowAPI::ConstantAST ast) + { + cout << "\t\t\tCONST AST" << endl; + target = ast.val().val; + return AST::Ptr(); + }; + + virtual AST::Ptr visit(DataflowAPI::VariableAST) + { + cout << "\t\t\tVARIABLE AST" << endl; + resolved = false; + return AST::Ptr(); + }; + + virtual AST::Ptr visit(DataflowAPI::RoseAST * r) + { + using namespace DataflowAPI; + + AST::Children newKids; + for(unsigned i=0;inumChildren();++i) + newKids.push_back(r->child(i)->accept(this)); + + switch(r->val().op) + { + case ROSEOperation::addOp: + + assert(newKids.size() == 2); + if(newKids[0]->getID() == AST::V_ConstantAST && + newKids[1]->getID() == AST::V_ConstantAST) + { + ConstantAST::Ptr c1 = ConstantAST::convert(newKids[0]); + ConstantAST::Ptr c2 = ConstantAST::convert(newKids[1]); + target = c1->val().val + c2->val().val; + return ConstantAST::create( + Constant(c1->val().val+c2->val().val)); + } + break; + default: + startup_printf("%s[%d] unhandled FindMainVisitor operation\n", + FILE__,__LINE__); + } + + return RoseAST::create(r->val(), newKids); + } + + virtual ASTPtr visit(DataflowAPI::ConstantAST * c) + { + return c->ptr(); + }; +}; + /* * Search for the Main Symbols in the list of symbols, Only in case * if the file is a shared object. If not present add them to the @@ -564,7 +632,6 @@ void image::findMain() // instruction insn; // insn.setInstruction( p ); Address mainAddress = 0; - cout << "Guess main:" << endl; // Create a temporary SymtabCodeSource that we can use for parsing. // We're going to throw it away when we're done so that we can re-sync @@ -580,7 +647,6 @@ void image::findMain() /* Get the code regions we are looking at */ std::set regions; scs.findRegions(entry_point, regions); - cout << "\t" << regions.size() << " regions were found" << endl; /* We should only get one region */ if(regions.size() != 1) @@ -590,21 +656,17 @@ void image::findMain() /* Parse the function we're looking at */ co.parse(region, entry_point, true); - cout << "\tParsing the region..." << endl; /* Get the parsed Function */ vector funcs; Function* func = co.findFuncByEntry(region, entry_point); assert(func); /* This should really exist now */ - cout << "\tGot function " << func->name() << endl; /* Use dataflow analysis here to determine the value of EDI */ const unsigned char* raw = p; instruction insn; insn.setInstruction(raw); Address insn_addr = entry_point; - cout << "\tStarting address: " << insn_addr << endl; - cout << "\tInstructions:" << endl; const unsigned char *last_insn = NULL; while(!insn.isCall()) @@ -622,8 +684,6 @@ void image::findMain() /* Calculate the address of the instruction */ insn_addr += last_insn - p; - cout << "\tAddr difference: " << (last_insn - p) << endl; - cout << "\tFinal address: " << insn_addr << endl; /* Decode the instruction */ InstructionAPI::InstructionDecoder* decoder = NULL; @@ -649,26 +709,22 @@ void image::findMain() std::vector assignments; Dyninst::AssignmentConverter assign_convert(true, true); assign_convert.convert(insn_ptr, insn_addr, func, b, assignments); - cout << "\t" << assignments.size() << " assignments were returned." << endl; - - - - // while( !insn.isCall() ) - // { - // lastP = p; - // p += insn.size(); - // insn.setInstruction( p ); - // } - - // We _really_ can't handle a call with nothing before it.... - // assert(lastP); - - // FIXME: this assumes that the instruction immediately before the call sets - // the main address - this may not be true. - // instruction preCall; - // preCall.setInstruction(lastP); - - // mainAddress = get_immediate_operand(&preCall); + if(assignments.size() >= 1) + { + Assignment::Ptr assignment = *assignments.begin(); + + std::pair res = DataflowAPI::SymEval::expand(assignment, false); + AST::Ptr ast = res.first; + // VariableAST::Ptr v = boost::static_pointer_cast(ast); + FindMainVisitor fmv; + ast->accept(&fmv); + if(fmv.resolved) + { + mainAddress = fmv.target; + } else { + mainAddress = 0x0; + } + } #else // Heuristic: main is the target of the 4th call in the text section using namespace Dyninst::InstructionAPI; From 984671e67252ed25b0e84191e16d27640ee9d2ca Mon Sep 17 00:00:00 2001 From: John Detter Date: Mon, 25 Jul 2016 16:13:12 -0500 Subject: [PATCH 007/180] Fixes for Ubuntu 16.04 --- dyninstAPI/src/image.C | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index 1e0d5b214a..715cc2de44 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -411,28 +411,14 @@ class FindMainVisitor : public ASTVisitor public: bool resolved; Address target; - FindMainVisitor() : resolved(true), target(0){} - - virtual AST::Ptr visit(DataflowAPI::ConstantAST ast) - { - cout << "\t\t\tCONST AST" << endl; - target = ast.val().val; - return AST::Ptr(); - }; - - virtual AST::Ptr visit(DataflowAPI::VariableAST) - { - cout << "\t\t\tVARIABLE AST" << endl; - resolved = false; - return AST::Ptr(); - }; + FindMainVisitor() : resolved(false), target(0){} virtual AST::Ptr visit(DataflowAPI::RoseAST * r) { using namespace DataflowAPI; AST::Children newKids; - for(unsigned i=0;inumChildren();++i) + for(unsigned i = 0; i < r->numChildren(); i++) newKids.push_back(r->child(i)->accept(this)); switch(r->val().op) @@ -446,8 +432,9 @@ class FindMainVisitor : public ASTVisitor ConstantAST::Ptr c1 = ConstantAST::convert(newKids[0]); ConstantAST::Ptr c2 = ConstantAST::convert(newKids[1]); target = c1->val().val + c2->val().val; + resolved = true; return ConstantAST::create( - Constant(c1->val().val+c2->val().val)); + Constant(c1->val().val + c2->val().val)); } break; default: @@ -460,6 +447,12 @@ class FindMainVisitor : public ASTVisitor virtual ASTPtr visit(DataflowAPI::ConstantAST * c) { + if(!target) + { + resolved = true; + target = c->val().val; + } + return c->ptr(); }; }; @@ -715,12 +708,14 @@ void image::findMain() std::pair res = DataflowAPI::SymEval::expand(assignment, false); AST::Ptr ast = res.first; + cout << "AST: " << ast->format() << endl; // VariableAST::Ptr v = boost::static_pointer_cast(ast); FindMainVisitor fmv; ast->accept(&fmv); if(fmv.resolved) { mainAddress = fmv.target; + cout << "\tResolved main: " << mainAddress << endl; } else { mainAddress = 0x0; } From e3dc450642721381177b6b8f4e7cb5d031606118 Mon Sep 17 00:00:00 2001 From: John Detter Date: Mon, 25 Jul 2016 16:29:29 -0500 Subject: [PATCH 008/180] Removed debug statements --- dyninstAPI/src/image.C | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index 715cc2de44..671de66ce1 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -700,7 +700,7 @@ void image::findMain() /* Let's get the assignment for this instruction. */ std::vector assignments; - Dyninst::AssignmentConverter assign_convert(true, true); + Dyninst::AssignmentConverter assign_convert(true, false); assign_convert.convert(insn_ptr, insn_addr, func, b, assignments); if(assignments.size() >= 1) { @@ -708,14 +708,14 @@ void image::findMain() std::pair res = DataflowAPI::SymEval::expand(assignment, false); AST::Ptr ast = res.first; - cout << "AST: " << ast->format() << endl; + // cout << "AST: " << ast->format() << endl; // VariableAST::Ptr v = boost::static_pointer_cast(ast); FindMainVisitor fmv; ast->accept(&fmv); if(fmv.resolved) { mainAddress = fmv.target; - cout << "\tResolved main: " << mainAddress << endl; + // cout << "\tResolved main: " << mainAddress << endl; } else { mainAddress = 0x0; } From 36bd1735cb8ce79eaaa1be477cf6ae72cdb2b1ef Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Tue, 26 Jul 2016 09:32:24 -0500 Subject: [PATCH 009/180] Even when the jump target is unknown, we should still apply tail call heuristics to check if the jump is a tail call. This can happen when the jump targets a unparsed function entry or the jump is an indirect tail call. --- parseAPI/src/IA_x86.C | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/parseAPI/src/IA_x86.C b/parseAPI/src/IA_x86.C index 16cb09af88..7abbb2b145 100644 --- a/parseAPI/src/IA_x86.C +++ b/parseAPI/src/IA_x86.C @@ -257,7 +257,8 @@ bool IA_IAPI::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, co target = *blocks.begin(); } else if (blocks.size() == 0) { // This case can happen when the jump target is a function entry, - // but we have not parsed the function yet + // but we have not parsed the function yet, + // or when this is an indirect jump target = NULL; } else { // If this case happens, it means the jump goes into overlapping instruction streams, @@ -272,13 +273,11 @@ bool IA_IAPI::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, co } } - // if target is still NULL, return false - if(target == NULL) return false; - if(curInsn()->getCategory() == c_BranchInsn && valid && callee && callee != context && + target && !context->contains(target) ) { From 7cd16d8d8179816f3d520a6a74d1434cbf94eaf0 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 26 Jul 2016 11:12:23 -0500 Subject: [PATCH 010/180] Add support for immediate pushes in StackAnalysis. --- dataflowAPI/src/stackanalysis.C | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 28e9783ba4..679a1220d0 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -1077,14 +1077,20 @@ void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, long writtenSlotHeight = spHeight.height() - word_size; Absloc writtenLoc(writtenSlotHeight, 0, NULL); - // Get copied register Expression::Ptr readExpr = insn->getOperand(0).getValue(); - assert(typeid(*readExpr) == typeid(RegisterAST)); - MachRegister readReg = boost::dynamic_pointer_cast( - readExpr)->getID(); - Absloc readLoc(readReg); - - xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); + if (typeid(*readExpr) == typeid(RegisterAST)) { + // Get copied register + MachRegister readReg = boost::dynamic_pointer_cast( + readExpr)->getID(); + Absloc readLoc(readReg); + xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); + } else if (typeid(*readExpr) == typeid(Immediate)) { + // Get pushed immediate + long immVal = readExpr->eval().convert(); + xferFuncs.push_back(TransferFunc::absFunc(writtenLoc, immVal)); + } else { + assert(false); + } } } } else if (insn->getOperation().getID() == e_pop && !insn->writesMemory()) { From 895d3fad7e59dc2096d8c74111a0606ee0b70a44 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 26 Jul 2016 13:31:37 -0700 Subject: [PATCH 011/180] dataflowAPI: space out template '>>' for pre-C++11 compatibility --- dataflowAPI/h/stackanalysis.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataflowAPI/h/stackanalysis.h b/dataflowAPI/h/stackanalysis.h index 6844569e14..788793bf62 100644 --- a/dataflowAPI/h/stackanalysis.h +++ b/dataflowAPI/h/stackanalysis.h @@ -331,7 +331,7 @@ class StackAnalysis { // To build intervals, we must replay the effect of each instruction. // To avoid sucking enormous time, we keep those transfer functions around... - typedef std::map> + typedef std::map > InstructionEffects; DATAFLOW_EXPORT StackAnalysis(); From 629db33e718a0ab65ed22f8c447f45f4c4519595 Mon Sep 17 00:00:00 2001 From: John Detter Date: Wed, 27 Jul 2016 03:14:40 -0500 Subject: [PATCH 012/180] Removed print statements --- dyninstAPI/src/image.C | 3 --- 1 file changed, 3 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index 671de66ce1..bf158bd7c0 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -708,14 +708,11 @@ void image::findMain() std::pair res = DataflowAPI::SymEval::expand(assignment, false); AST::Ptr ast = res.first; - // cout << "AST: " << ast->format() << endl; - // VariableAST::Ptr v = boost::static_pointer_cast(ast); FindMainVisitor fmv; ast->accept(&fmv); if(fmv.resolved) { mainAddress = fmv.target; - // cout << "\tResolved main: " << mainAddress << endl; } else { mainAddress = 0x0; } From 8f85a86caa63d595cddf9a4cc4d8e2695b983bdc Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Thu, 28 Jul 2016 09:58:52 -0500 Subject: [PATCH 013/180] Indirect tail calls can be PC-relative and should be treated as indirect calls during relocation --- .../Relocation/Transformers/Movement-adhoc.C | 4 ++-- dyninstAPI/src/Relocation/Widgets/CFWidget.C | 4 +++- dyninstAPI/src/parse-cfg.C | 17 ++++++++++++++++- dyninstAPI/src/parse-cfg.h | 1 + 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C index 2826654026..f9fe7848f1 100644 --- a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C +++ b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C @@ -59,7 +59,8 @@ bool adhocMovementTransformer::process(RelocBlock *cur, RelocGraph *cfg) { RelocBlock::WidgetList &elements = cur->elements(); - relocation_cerr << "PCRelTrans: processing block " + relocation_cerr << "PCRelTrans: processing block (ID= " + << cur->id() << ") " << cur << " with " << elements.size() << " elements." << endl; @@ -93,7 +94,6 @@ bool adhocMovementTransformer::process(RelocBlock *cur, RelocGraph *cfg) { // Cache this so we don't re-decode... InsnPtr insn = (*iter)->insn(); - if (!insn) continue; Address target = 0; diff --git a/dyninstAPI/src/Relocation/Widgets/CFWidget.C b/dyninstAPI/src/Relocation/Widgets/CFWidget.C index e6d1eb311d..d0b39c88fa 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/CFWidget.C @@ -275,7 +275,9 @@ bool CFWidget::generate(const codeGen &templ, // this for the memory emulation effort. Huzzah! if (!generateAddressTranslator(buffer, templ, reg, trace)) return false; - if (isCall_) { + // If this is an indirect tail call, we still treat it + // as an indirect call + if (isCall_ || trace->block()->llb()->isIndirectTailCallBlock()) { if (!generateIndirectCall(buffer, reg, insn_, diff --git a/dyninstAPI/src/parse-cfg.C b/dyninstAPI/src/parse-cfg.C index cc729f3681..32711fef6b 100644 --- a/dyninstAPI/src/parse-cfg.C +++ b/dyninstAPI/src/parse-cfg.C @@ -358,7 +358,22 @@ bool parse_block::isCallBlock() } return false; } - +bool parse_block::isIndirectTailCallBlock() +{ + const Block::edgelist & trgs = targets(); + if(!trgs.empty()) + { + for (Block::edgelist::const_iterator eit = trgs.begin(); + eit != trgs.end(); + eit++) + { + if ((*eit)->type() == INDIRECT && (*eit)->interproc()) { + return true; + } + } + } + return false; +} image *parse_block::img() { vector funcs; diff --git a/dyninstAPI/src/parse-cfg.h b/dyninstAPI/src/parse-cfg.h index 276d583071..d29a9ced82 100644 --- a/dyninstAPI/src/parse-cfg.h +++ b/dyninstAPI/src/parse-cfg.h @@ -79,6 +79,7 @@ class parse_block : public codeRange, public ParseAPI::Block { bool isShared() const { return containingFuncs() > 1; } bool isExitBlock(); bool isCallBlock(); + bool isIndirectTailCallBlock(); bool isEntryBlock(parse_func * f) const; parse_func *getEntryFunc() const; // func starting with this bock From f755baceaeadb84fd1ca3b03a6713720f01a6d3e Mon Sep 17 00:00:00 2001 From: John Detter Date: Fri, 29 Jul 2016 14:25:23 -0500 Subject: [PATCH 014/180] Matt's patch applied --- dataflowAPI/src/stackanalysis.C | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 28e9783ba4..68a7c5eb6c 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -1338,7 +1338,8 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, // op1: reg + imm // or // op1: reg - // + // or + // op1: imm stackanalysis_printf("\t\t\t handleLEA, insn = %s\n", insn->format().c_str()); @@ -1348,7 +1349,7 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, insn->getOperand(0).getWriteSet(writtenSet); insn->getOperand(1).getReadSet(readSet); assert(writtenSet.size() == 1); - assert(readSet.size() == 1 || readSet.size() == 2); + assert(readSet.size() == 0 || readSet.size() == 1 || readSet.size() == 2); MachRegister written = (*writtenSet.begin())->getID(); Absloc writeloc(written); @@ -1360,7 +1361,13 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, stackanalysis_printf("\t\t\t\t srcOperand = %s\n", srcExpr->format().c_str()); - if (readSet.size() == 1) { + if (readSet.size() == 0) { + // op1: imm + assert(typeid(*srcExpr) == typeid(Immediate)); + long immVal = srcExpr->eval().convert(); + xferFuncs.push_back(TransferFunc::absFunc(writeloc, immVal)); + retopBaseSubReg(written, xferFuncs); + } else if (readSet.size() == 1) { InstructionAPI::Expression::Ptr regExpr, scaleExpr, deltaExpr; bool foundScale = false; bool foundDelta = false; From db47d0f19f40379235ba1247eb66fbbe6108fffa Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 2 Aug 2016 17:52:32 -0500 Subject: [PATCH 015/180] Added asserts in liveness.C to prevent buffer underreads for registers that aren't defined. Partial fix for #114 --- dataflowAPI/src/liveness.C | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dataflowAPI/src/liveness.C b/dataflowAPI/src/liveness.C index f6b9f8cd2a..b02254c92b 100644 --- a/dataflowAPI/src/liveness.C +++ b/dataflowAPI/src/liveness.C @@ -415,7 +415,9 @@ bool LivenessAnalyzer::query(Location loc, Type type, bitArray &bitarray) { bool LivenessAnalyzer::query(Location loc, Type type, const MachRegister& machReg, bool &live){ bitArray liveRegs; if (query(loc, type, liveRegs)){ - live = liveRegs[getIndex(machReg)]; + int index = getIndex(machReg); + assert(index >= 0); + live = liveRegs[index]; return true; } return false; @@ -470,7 +472,9 @@ ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, } else{ base = changeIfMMX(base); - ret.read[getIndex(base)] = true; + int index = getIndex(base); + assert(index >= 0); + ret.read[index] = true; } } liveness_printf("Write Registers: \n"); @@ -507,8 +511,10 @@ ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, } else{ base = changeIfMMX(base); - ret.written[getIndex(base)] = true; - if ((cur != base && cur.size() < 4) || isMMX(base)) ret.read[getIndex(base)] = true; + int index = getIndex(base); + assert(index >= 0); + ret.written[index] = true; + if ((cur != base && cur.size() < 4) || isMMX(base)) ret.read[index] = true; } } InsnCategory category = curInsn->getCategory(); From 1feabf51144c8a8c1aafd0c351d6e40866296397 Mon Sep 17 00:00:00 2001 From: John Detter Date: Wed, 3 Aug 2016 13:48:30 -0500 Subject: [PATCH 016/180] findMain will now return 0 on success, -1 on failure instead of asserting. The visitor has been improved and should be able to recognize more false positives. Verbose debugging output has been converted to startup_printfs. --- dyninstAPI/src/image.C | 90 ++++++++++++++++++++++++++++-------------- dyninstAPI/src/image.h | 2 +- 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index bf158bd7c0..55aab50775 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -410,8 +410,9 @@ class FindMainVisitor : public ASTVisitor public: bool resolved; + bool hardFault; Address target; - FindMainVisitor() : resolved(false), target(0){} + FindMainVisitor() : resolved(false), hardFault(false), target(0) {} virtual AST::Ptr visit(DataflowAPI::RoseAST * r) { @@ -431,8 +432,11 @@ class FindMainVisitor : public ASTVisitor { ConstantAST::Ptr c1 = ConstantAST::convert(newKids[0]); ConstantAST::Ptr c2 = ConstantAST::convert(newKids[1]); - target = c1->val().val + c2->val().val; - resolved = true; + if(!hardFault) + { + target = c1->val().val + c2->val().val; + resolved = true; + } return ConstantAST::create( Constant(c1->val().val + c2->val().val)); } @@ -447,7 +451,8 @@ class FindMainVisitor : public ASTVisitor virtual ASTPtr visit(DataflowAPI::ConstantAST * c) { - if(!target) + /* We can only handle constant values */ + if(!target && !hardFault) { resolved = true; target = c->val().val; @@ -455,14 +460,24 @@ class FindMainVisitor : public ASTVisitor return c->ptr(); }; + + virtual ASTPtr visit(DataflowAPI::VariableAST* v) + { + /* If we visit a variable node, we can't do any analysis */ + hardFault = true; + resolved = false; + target = 0; + + return v->ptr(); + } }; -/* +/** * Search for the Main Symbols in the list of symbols, Only in case * if the file is a shared object. If not present add them to the - * list + * list. Returns zero on success, nonzero otherwise. */ -void image::findMain() +int image::findMain() { #if defined(ppc32_linux) || defined(ppc32_bgp) || defined(ppc64_linux) using namespace Dyninst::InstructionAPI; @@ -475,7 +490,7 @@ void image::findMain() bool foundMain = false; bool foundStart = false; bool foundFini = false; - //check if 'main' is in allsymbols + // check if 'main' is in allsymbols vector funcs; if (linkedFile->findFunctionsByName(funcs, "main") || linkedFile->findFunctionsByName(funcs, "_main")) @@ -487,11 +502,11 @@ void image::findMain() Region *eReg = NULL; bool foundText = linkedFile->findRegion(eReg, ".text"); - if (foundText == false) { - return; - } - if( !foundMain ) + if (!foundText) + return -1; + + if(!foundMain) { logLine("No main symbol found: attempting to create symbol for main\n"); @@ -507,7 +522,7 @@ void image::findMain() scs.findRegions(eAddr,regions); if(regions.empty()) { // express puzzlement - return; + return -1; } SymtabCodeRegion * reg = static_cast(*regions.begin()); @@ -515,7 +530,7 @@ void image::findMain() tco.findFuncByEntry(reg,eAddr); if(!func) { // again, puzzlement - return; + return -1; } Block * b = NULL; @@ -530,16 +545,16 @@ void image::findMain() startup_printf("%s[%d] _start has unexpected number (%d) of" " call edges, bailing on findMain()\n", FILE__,__LINE__,calls.size()); - return; + return -1; } - if (!b) return; + if (!b) return -1; Address mainAddress = evaluate_main_address(linkedFile,func,b); mainAddress = deref_opd(linkedFile, mainAddress); if(0 == mainAddress || !scs.isValidAddress(mainAddress)) { startup_printf("%s[%d] failed to find main\n",FILE__,__LINE__); - return; + return -1; } else { startup_printf("%s[%d] found main at %lx\n", FILE__,__LINE__,mainAddress); @@ -555,6 +570,7 @@ void image::findMain() linkedFile->addSymbol(newSym); } } + #elif defined(i386_unknown_linux2_0) \ || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \ || (defined(os_freebsd) \ @@ -585,12 +601,13 @@ void image::findMain() Address eAddr = linkedFile->getEntryOffset(); Region *eReg = linkedFile->findEnclosingRegion(eAddr); - if (!eReg) { - return; - } + + if (!eReg) + return -1; + Address eStart = eReg->getMemOffset(); - if( !foundMain ) + if(!foundMain) { logLine( "No main symbol found: creating symbol for main\n" ); @@ -622,8 +639,6 @@ void image::findMain() break; } - // instruction insn; - // insn.setInstruction( p ); Address mainAddress = 0; // Create a temporary SymtabCodeSource that we can use for parsing. @@ -634,7 +649,7 @@ void image::findMain() CodeObject co(&scs); #if !defined(os_freebsd) - + /* Find the entry point, where we start our analysis */ Address entry_point = (Address)linkedFile->getEntryOffset(); /* Get the code regions we are looking at */ @@ -643,7 +658,11 @@ void image::findMain() /* We should only get one region */ if(regions.size() != 1) - assert(!"Overlapping or non existant regions!"); + { + startup_printf("%s[%u]: Overlapping or non existant regions!\n", + FILE__, __LINE__); + return -1; + } CodeRegion* region = *regions.begin(); assert(region); @@ -653,7 +672,12 @@ void image::findMain() /* Get the parsed Function */ vector funcs; Function* func = co.findFuncByEntry(region, entry_point); - assert(func); /* This should really exist now */ + if(!func) + { + startup_printf("%s[%u]: No functions found in our region.\n", + FILE__, __LINE__); + return -1; + } /* Use dataflow analysis here to determine the value of EDI */ const unsigned char* raw = p; @@ -671,8 +695,10 @@ void image::findMain() if(!last_insn) /* We cannot do analysis on this */ { - assert(!"findMain analysis has failed"); - return; + startup_printf("%s[%u]: Our main analysis doesn't apply to " + "this compiler.\n", + FILE__, __LINE__); + return -1; } /* Calculate the address of the instruction */ @@ -694,7 +720,11 @@ void image::findMain() assert(region->contains(insn_addr)); std::set blocks; co.findBlocks(region, insn_addr, blocks); - assert(blocks.size() == 1); + if(blocks.size() == 1) + { + startup_printf("%s[%u]: WARNING: overlapping blocks.\n", + FILE__, __LINE__); + } Block* b = *blocks.begin(); assert(b); @@ -899,6 +929,8 @@ void image::findMain() } } #endif + + return 0; /* Success */ } /* diff --git a/dyninstAPI/src/image.h b/dyninstAPI/src/image.h index 921dc40723..17ec4daeb1 100644 --- a/dyninstAPI/src/image.h +++ b/dyninstAPI/src/image.h @@ -448,7 +448,7 @@ class image : public codeRange { // Platform-specific discovery of the "main" function // FIXME There is a minor but fundamental design flaw that // needs to be resolved wrt findMain returning void. - void findMain(); + int findMain(); bool determineImageType(); bool addSymtabVariables(); From 7bcafa0643b1325da42a9c553d95458a13648d94 Mon Sep 17 00:00:00 2001 From: John Detter Date: Wed, 3 Aug 2016 13:55:30 -0500 Subject: [PATCH 017/180] Added more startup printf statements for findMain success or failure. --- dyninstAPI/src/image.C | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index 55aab50775..f5cb7d8b41 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -1513,7 +1513,14 @@ image::image(fileDescriptor &desc, //Now add Main and Dynamic Symbols if they are not present startup_printf("%s[%d]: before findMain\n", FILE__, __LINE__); - findMain(); + if(findMain()) + { + startup_printf("%s[%d]: ERROR: findMain analysis has failed!\n", + FILE__, __LINE__); + } else { + startup_printf("%s[%d]: findMain analysis succeeded.\n", + FILE__, __LINE__); + } // Initialize ParseAPI filt = NULL; From b8596ad4023ec40ac07e669ff8ea3ec06e262703 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 9 Aug 2016 14:11:11 -0700 Subject: [PATCH 018/180] proccontrol: make computeAddrWidth independent of endianness In linux_process::computeAddrWidth(), it's trying to guess the address size without disk access, but commit c8d7481 started opening the exe to figure out its endianness. This is especially a problem if a process was attached without specifying its executable. We can modify the auxv scan to look at *both* little-endian and big- endian words. If either are all zero, we know this is a 64-bit process. We could even report which endian it is from this, although we still wouldn't know that for 32-bit processes. --- proccontrol/src/linux.C | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C index 4502e357f7..407a77ec6e 100644 --- a/proccontrol/src/linux.C +++ b/proccontrol/src/linux.C @@ -884,8 +884,9 @@ int linux_process::computeAddrWidth() * of name word will be 0x0 on 64 bit processes. On 32-bit process this * word will contain a value, of which some should be non-zero. * - * We'll thus check every word that is 1 mod 4. If all are 0x0 we assume we're - * looking at a 64-bit process. + * We'll thus check every word that is 1 mod 4 for little-endian machines, + * or 0 mod 4 for big-endian. If all words of either stripe are 0x0, we + * assume we're looking at a 64-bit process. **/ uint32_t buffer[256]; char auxv_name[64]; @@ -898,25 +899,21 @@ int linux_process::computeAddrWidth() return -1; } - long int result = read(fd, buffer, sizeof(buffer)); - long int words_read = result / sizeof(uint32_t); - int word_size = 8; + ssize_t result = read(fd, buffer, sizeof(buffer)); + ssize_t words_read = (result / sizeof(uint32_t)) & ~3; + close(fd); // We want to check the highest 4 bytes of each integer // On big-endian systems, these come first in memory - SymReader *objSymReader = getSymReader()->openSymbolReader(getExecutable()); - int start_index = objSymReader->isBigEndianDataEncoding() ? 0 : 1; - - for (long int i=start_index; i Date: Tue, 9 Aug 2016 14:15:52 -0700 Subject: [PATCH 019/180] proccontrol: improve Codegen's exe lookup Commit c8d7481 made `Codegen::generate` start opening the executable to determine the ABI version of the process. However, the llproc exe isn't always set, if the process was attached without specifying it. We can instead get the right path from `proc_->libraries().getExecutable()`. --- proccontrol/src/loadLibrary/codegen.C | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/proccontrol/src/loadLibrary/codegen.C b/proccontrol/src/loadLibrary/codegen.C index 9d545a7a5f..a29b61450a 100644 --- a/proccontrol/src/loadLibrary/codegen.C +++ b/proccontrol/src/loadLibrary/codegen.C @@ -33,9 +33,11 @@ bool Codegen::generate() { buffer_.initialize(codeStart_, size); - SymReader *objSymReader = proc_->llproc()->getSymReader()->openSymbolReader(proc_->llproc()->getExecutable()); abimajversion_ = abiminversion_ = 0; - objSymReader->getABIVersion(abimajversion_, abiminversion_); + auto exe = proc_->libraries().getExecutable(); + SymReader *objSymReader = proc_->llproc()->getSymReader()->openSymbolReader(exe->getName()); + if (objSymReader) + objSymReader->getABIVersion(abimajversion_, abiminversion_); if (!generateInt()) return false; From 5dbfd782233d0e8d5f7d0dd7dc6466d0d2f5e5b2 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Thu, 14 Jul 2016 08:40:52 -0500 Subject: [PATCH 020/180] Rewrite default instruction handler. The original handler was too liberal, only rounding written registers to TOP/BOTTOM. The new handler computes a join over all read registers and memory locations, rounds the result to TOP or BOTTOM, and then assigns the rounded value to all written registers and memory locations. --- dataflowAPI/h/stackanalysis.h | 32 +++---- dataflowAPI/src/stackanalysis.C | 143 +++++++++++++++++++++++++------- 2 files changed, 131 insertions(+), 44 deletions(-) diff --git a/dataflowAPI/h/stackanalysis.h b/dataflowAPI/h/stackanalysis.h index 788793bf62..2507c1a236 100644 --- a/dataflowAPI/h/stackanalysis.h +++ b/dataflowAPI/h/stackanalysis.h @@ -61,17 +61,17 @@ // These are _NOT_ in the Dyninst namespace... namespace Dyninst { - namespace ParseAPI { - class Function; - class Block; - class Edge; - }; - namespace InstructionAPI { - class Instruction; - class Expression; - }; - - + namespace ParseAPI { + class Function; + class Block; + class Edge; + }; + namespace InstructionAPI { + class Instruction; + class Expression; + }; + + class StackAnalysis { public: typedef boost::shared_ptr InstructionPtr; @@ -392,9 +392,10 @@ class StackAnalysis { TransferFuncs &xferFuncs); void handlePushPopFlags(int sign, TransferFuncs &xferFuncs); void handlePushPopRegs(int sign, TransferFuncs &xferFuncs); - void handlePowerAddSub(InstructionPtr insn, int sign, - TransferFuncs &xferFuncs); - void handlePowerStoreUpdate(InstructionPtr insn, TransferFuncs &xferFuncs); + void handlePowerAddSub(InstructionPtr insn, ParseAPI::Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs); + void handlePowerStoreUpdate(InstructionPtr insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); void handleMov(InstructionPtr insn, ParseAPI::Block *block, const Offset off, TransferFuncs &xferFuncs); void handleZeroExtend(InstructionPtr insn, ParseAPI::Block *block, @@ -406,7 +407,8 @@ class StackAnalysis { TransferFuncs &xferFuncs); void handleDiv(InstructionPtr insn, TransferFuncs &xferFuncs); void handleMul(InstructionPtr insn, TransferFuncs &xferFuncs); - void handleDefault(InstructionPtr insn, TransferFuncs &xferFuncs); + void handleDefault(InstructionPtr insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); long extractDelta(InstructionAPI::Result deltaRes); bool getSubReg(const MachRegister ®, MachRegister &subreg); diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index be20946d5b..1dd3e7f5fa 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -422,7 +422,7 @@ void StackAnalysis::computeInsnEffects(ParseAPI::Block *block, if (isCall(insn)) { if (handleNormalCall(insn, block, off, xferFuncs)) return; else if (handleThunkCall(insn, xferFuncs)) return; - else return handleDefault(insn, xferFuncs); + else return handleDefault(insn, block, off, xferFuncs); } int sign = 1; @@ -462,14 +462,14 @@ void StackAnalysis::computeInsnEffects(ParseAPI::Block *block, break; case e_popad: // This nukes all registers - handleDefault(insn, xferFuncs); + handleDefault(insn, block, off, xferFuncs); break; case power_op_addi: case power_op_addic: - handlePowerAddSub(insn, sign, xferFuncs); + handlePowerAddSub(insn, block, off, sign, xferFuncs); break; case power_op_stwu: - handlePowerStoreUpdate(insn, xferFuncs); + handlePowerStoreUpdate(insn, block, off, xferFuncs); break; case e_mov: case e_movsd_sse: @@ -498,7 +498,7 @@ void StackAnalysis::computeInsnEffects(ParseAPI::Block *block, handleMul(insn, xferFuncs); break; default: - handleDefault(insn, xferFuncs); + handleDefault(insn, block, off, xferFuncs); } } @@ -1567,13 +1567,12 @@ void StackAnalysis::handlePushPopRegs(int sign, TransferFuncs &xferFuncs) { copyBaseSubReg(sp(), xferFuncs); } -void StackAnalysis::handlePowerAddSub(Instruction::Ptr insn, int sign, - TransferFuncs &xferFuncs) { - +void StackAnalysis::handlePowerAddSub(Instruction::Ptr insn, Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs) { // Add/subtract are op0 = op1 +/- op2; we'd better read the stack pointer as // well as writing it if (!insn->isRead(theStackPtr) || !insn->isWritten(theStackPtr)) { - return handleDefault(insn, xferFuncs); + return handleDefault(insn, block, off, xferFuncs); } Operand arg = insn->getOperand(2); @@ -1594,11 +1593,10 @@ void StackAnalysis::handlePowerAddSub(Instruction::Ptr insn, int sign, } } -void StackAnalysis::handlePowerStoreUpdate(Instruction::Ptr insn, - TransferFuncs &xferFuncs) { - +void StackAnalysis::handlePowerStoreUpdate(Instruction::Ptr insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { if (!insn->isWritten(theStackPtr)) { - return handleDefault(insn, xferFuncs); + return handleDefault(insn, block, off, xferFuncs); } std::set memWriteAddrs; @@ -1976,22 +1974,111 @@ void StackAnalysis::handleSpecialSignExtend(Instruction::Ptr insn, copyBaseSubReg(writtenReg, xferFuncs); } -void StackAnalysis::handleDefault(Instruction::Ptr insn, - TransferFuncs &xferFuncs) { - std::set written; - insn->getWriteSet(written); - for (auto iter = written.begin(); iter != written.end(); ++iter) { +// Handle instructions for which we have no special handling implemented. Be +// conservative for safety. +void StackAnalysis::handleDefault(Instruction::Ptr insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { + // Form sets of read/written Abslocs + std::set writtenRegs; + std::set readRegs; + insn->getWriteSet(writtenRegs); + insn->getReadSet(readRegs); + std::set writtenLocs; + std::set readLocs; + for (auto iter = writtenRegs.begin(); iter != writtenRegs.end(); iter++) { const MachRegister ® = (*iter)->getID(); - if ((signed int) reg.regClass() == x86::FLAG || - (signed int) reg.regClass() == x86_64::FLAG) { + if ((signed int) reg.regClass() == x86::GPR || + (signed int) reg.regClass() == x86_64::GPR) { + writtenLocs.insert(Absloc(reg)); + } + } + for (auto iter = readRegs.begin(); iter != readRegs.end(); iter++) { + const MachRegister ® = (*iter)->getID(); + if ((signed int) reg.regClass() == x86::GPR || + (signed int) reg.regClass() == x86_64::GPR) { + readLocs.insert(Absloc(reg)); + } + } + if (insn->readsMemory()) { + // Add any determinable read locations to readLocs + std::set memExprs; + insn->getMemoryReadOperands(memExprs); + for (auto iter = memExprs.begin(); iter != memExprs.end(); iter++) { + const Expression::Ptr &memExpr = *iter; + StateEvalVisitor visitor; + if (intervals_ == NULL) { + visitor = StateEvalVisitor(off, insn, NULL); + } else { + visitor = StateEvalVisitor(off, insn, &(*intervals_)[block][off]); + } + memExpr->apply(&visitor); + if (visitor.isDefined()) { + // Read location is determinable + std::pair resultPair = visitor.getResult(); + Absloc readLoc; + if (resultPair.second) { + // Read from stack slot + readLoc = Absloc(resultPair.first, 0, NULL); + } else { + // Read from static address + readLoc = Absloc(resultPair.first); + } + readLocs.insert(readLoc); + } + } + } + if (insn->writesMemory()) { + // Add any determinable written locations to writtenLocs + std::set memExprs; + insn->getMemoryWriteOperands(memExprs); + for (auto iter = memExprs.begin(); iter != memExprs.end(); iter++) { + const Expression::Ptr &memExpr = *iter; + StateEvalVisitor visitor; + if (intervals_ == NULL) { + visitor = StateEvalVisitor(off, insn, NULL); + } else { + visitor = StateEvalVisitor(off, insn, &(*intervals_)[block][off]); + } + memExpr->apply(&visitor); + if (visitor.isDefined()) { + // Written location is determinable + std::pair resultPair = visitor.getResult(); + Absloc writtenLoc; + if (resultPair.second) { + // Write to stack slot + writtenLoc = Absloc(resultPair.first, 0, NULL); + } else { + // Write to static address + writtenLoc = Absloc(resultPair.first); + } + writtenLocs.insert(writtenLoc); + } + } + } + + // Now that we have a complete set of read/written Abslocs, we assign the + // written Abslocs to be a conservative combination of the read Abslocs. + for (auto wIter = writtenLocs.begin(); wIter != writtenLocs.end(); wIter++) { + const Absloc &writtenLoc = *wIter; + if (readLocs.empty()) { + // We can get here in two situations: (1) no locations are read, or (2) + // only non-GPRs and undeterminable memory locations are read. In + // either case, we assume the written value is not a stack height. + xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); + if (writtenLoc.type() == Absloc::Register) { + retopBaseSubReg(writtenLoc.reg(), xferFuncs); + } continue; } - Absloc loc(reg); - xferFuncs.push_back(TransferFunc::copyFunc(loc, loc, true)); - copyBaseSubReg(reg, xferFuncs); - stackanalysis_printf( - "\t\t\t Unhandled insn %s detected: %s set to topBottom\n", - insn->format().c_str(), (*iter)->getID().name().c_str()); + std::map> fromRegs; + for (auto rIter = readLocs.begin(); rIter != readLocs.end(); rIter++) { + const Absloc &readLoc = *rIter; + fromRegs[readLoc] = std::make_pair(1, true); + } + xferFuncs.push_back(TransferFunc::sibFunc(fromRegs, 0, writtenLoc)); + if (writtenLoc.type() == Absloc::Register) { + copyBaseSubReg(writtenLoc.reg(), xferFuncs); + } } } @@ -2032,7 +2119,7 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, gpr = ppc64::GPR; break; default: - handleDefault(insn, xferFuncs); + handleDefault(insn, block, off, xferFuncs); return true; } if ((*iter).first.regClass() == gpr) { @@ -2761,8 +2848,6 @@ StackAnalysis::TransferFunc StackAnalysis::TransferFunc::summaryAccumulate( return input; } - // Copies can be tricky - // apply copy logic only if registers are different if (isCopy()) { // We need to record that we want to take the inflow height // of a different register. From 3da53fcc59e5c74570d4c6d34f62a02e047c0423 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Thu, 14 Jul 2016 08:45:57 -0500 Subject: [PATCH 021/180] Remove EDX from x86 return registers. While RDX is considered a secondary return register in x86_64, EDX is not considered a secondary return register in x86. --- dataflowAPI/src/ABI.C | 1 - 1 file changed, 1 deletion(-) diff --git a/dataflowAPI/src/ABI.C b/dataflowAPI/src/ABI.C index 0582ce86e8..9389109723 100644 --- a/dataflowAPI/src/ABI.C +++ b/dataflowAPI/src/ABI.C @@ -182,7 +182,6 @@ void ABI::initialize32(){ returnRegs_ = getBitArray(machRegIndex_x86().size()); returnRegs_[machRegIndex_x86()[x86::eax]] = true; - returnRegs_[machRegIndex_x86()[x86::edx]] = true; returnRead_ = getBitArray(machRegIndex_x86().size()); From 2e8bc43db402435281454adbc64c2010a134d13e Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Thu, 14 Jul 2016 09:01:29 -0500 Subject: [PATCH 022/180] Stop following catch edges during stack analysis. Following catch edges results in garbage stack analysis results since our current CFGs simply place catch edges at exit points of the function. In reality such edges do not exist. --- dataflowAPI/src/stackanalysis.C | 19 +++++++++---------- .../Relocation/Transformers/Movement-adhoc.C | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 1dd3e7f5fa..4a57177dd6 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -205,11 +205,11 @@ void StackAnalysis::summarizeBlocks() { } } -struct intra_nosink : public ParseAPI::EdgePredicate { +struct intra_nosink_nocatch : public ParseAPI::EdgePredicate { virtual bool operator()(Edge* e) { static Intraproc i; static NoSinkPredicate n; - return i(e) && n(e); + return i(e) && n(e) && e->type() != CATCH; } }; @@ -218,7 +218,7 @@ void add_target(std::queue& worklist, Edge* e) { } void StackAnalysis::fixpoint() { - intra_nosink epred2; + intra_nosink_nocatch epred2; std::queue worklist; worklist.push(func->entry()); @@ -307,7 +307,7 @@ bool StackAnalysis::getFunctionSummary(TransferSet &summary) { void StackAnalysis::summaryFixpoint() { - intra_nosink epred2; + intra_nosink_nocatch epred2; std::queue worklist; worklist.push(func->entry()); @@ -367,10 +367,9 @@ void StackAnalysis::summarize() { if (intervals_ != NULL) delete intervals_; intervals_ = new Intervals(); - Function::blocklist bs = func->blocks(); - for (auto bit = bs.begin(); bit != bs.end(); ++bit) { - Block *block = *bit; - AbslocState input = blockInputs[block]; + for (auto bit = blockInputs.begin(); bit != blockInputs.end(); ++bit) { + Block *block = bit->first; + AbslocState input = bit->second; std::map::iterator iter; for (iter = (*insnEffects)[block].begin(); @@ -2278,7 +2277,7 @@ void StackAnalysis::meetInputs(Block *block, AbslocState& blockInput, //Intraproc epred; // ignore calls, returns in edge iteration //NoSinkPredicate epred2(&epred); // ignore sink node (unresolvable) - intra_nosink epred2; + intra_nosink_nocatch epred2; stackanalysis_printf("\t ... In edges: "); const Block::edgelist & inEdges = block->sources(); @@ -2301,7 +2300,7 @@ void StackAnalysis::meetSummaryInputs(Block *block, TransferSet &blockInput, //Intraproc epred; // ignore calls, returns in edge iteration //NoSinkPredicate epred2(&epred); // ignore sink node (unresolvable) - intra_nosink epred2; + intra_nosink_nocatch epred2; stackanalysis_printf("\t ... In edges: "); const Block::edgelist & inEdges = block->sources(); diff --git a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C index f9fe7848f1..59e42b7675 100644 --- a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C +++ b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C @@ -78,7 +78,7 @@ bool adhocMovementTransformer::process(RelocBlock *cur, RelocGraph *cfg) { assert(offVec); if (!cur->func()->hasValidOffsetVector()) { - // We should not be able to get here, but enforce that we do don't + // We should not be able to get here, but enforce that we don't return false; } From 67be8fd70b52a225849abd931fece7ec895fe899 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Thu, 14 Jul 2016 09:20:26 -0500 Subject: [PATCH 023/180] Assume XMM registers contain floating-point values. --- dataflowAPI/src/stackanalysis.C | 77 +++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 4a57177dd6..4ab2ce1107 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -1242,12 +1242,20 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, if (readSet.size() > 0) { // Case 3a assert(readSet.size() == 1); - std::map> terms; - Absloc src((*readSet.begin())->getID()); - Absloc &dest = writtenLoc; - terms[src] = make_pair(sign, false); - terms[dest] = make_pair(1, false); - xferFuncs.push_back(TransferFunc::sibFunc(terms, 0, dest)); + const MachRegister &srcReg = (*readSet.begin())->getID(); + if ((signed int) srcReg.regClass() == x86::XMM || + (signed int) srcReg.regClass() == x86_64::XMM) { + // Assume XMM registers only contain FP values, not pointers + xferFuncs.push_back(TransferFunc::copyFunc(writtenLoc, writtenLoc, + true)); + } else { + std::map> terms; + Absloc src(srcReg); + Absloc &dest = writtenLoc; + terms[src] = make_pair(sign, false); + terms[dest] = make_pair(1, false); + xferFuncs.push_back(TransferFunc::sibFunc(terms, 0, dest)); + } } else { // Case 5a Expression::Ptr immExpr = operands[1].getValue(); @@ -1261,9 +1269,16 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, // Cases 1, 2, and 4 assert(writeSet.size() == 1); - MachRegister written = (*writeSet.begin())->getID(); + const MachRegister &written = (*writeSet.begin())->getID(); Absloc writtenLoc(written); + if ((signed int) written.regClass() == x86::XMM || + (signed int) written.regClass() == x86_64::XMM) { + // Assume XMM registers only contain FP values, not pointers + xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); + return; + } + if (insn->readsMemory()) { // Case 2 stackanalysis_printf("\t\t\tAdd/sub from: %s\n", @@ -1319,12 +1334,20 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, copyBaseSubReg(written, xferFuncs); } else { // Case 1 - std::map> terms; - Absloc src((*readSet.begin())->getID()); - Absloc &dest = writtenLoc; - terms[src] = make_pair(sign, false); - terms[dest] = make_pair(1, false); - xferFuncs.push_back(TransferFunc::sibFunc(terms, 0, dest)); + const MachRegister &srcReg = (*readSet.begin())->getID(); + if ((signed int) srcReg.regClass() == x86::XMM || + (signed int) srcReg.regClass() == x86_64::XMM) { + // Assume XMM registers only contain FP values, not pointers + xferFuncs.push_back(TransferFunc::copyFunc(writtenLoc, writtenLoc, + true)); + } else { + std::map> terms; + Absloc src(srcReg); + Absloc &dest = writtenLoc; + terms[src] = make_pair(sign, false); + terms[dest] = make_pair(1, false); + xferFuncs.push_back(TransferFunc::sibFunc(terms, 0, dest)); + } copyBaseSubReg(written, xferFuncs); } } @@ -1703,8 +1726,15 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, if (readRegs.size() > 0) { // Case 4a assert(readRegs.size() == 1); - Absloc from((*readRegs.begin())->getID()); - xferFuncs.push_back(TransferFunc::copyFunc(from, writtenLoc)); + const MachRegister ® = (*readRegs.begin())->getID(); + if ((signed int) reg.regClass() == x86::XMM || + (signed int) reg.regClass() == x86_64::XMM) { + // Assume XMM registers only contain FP values, not pointers + xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); + } else { + Absloc from(reg); + xferFuncs.push_back(TransferFunc::copyFunc(from, writtenLoc)); + } } else { // Case 5a Expression::Ptr immExpr = operands[1].getValue(); @@ -1719,9 +1749,16 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, // Only Cases 1, 2, and 3 can reach this point. // As a result, we know there's exactly one written register. assert(writtenRegs.size() == 1); - MachRegister written = (*writtenRegs.begin())->getID(); + const MachRegister &written = (*writtenRegs.begin())->getID(); Absloc writtenLoc(written); + if ((signed int) written.regClass() == x86::XMM || + (signed int) written.regClass() == x86_64::XMM) { + // Assume XMM registers only contain FP values, not pointers + xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); + return; + } + if (insn->readsMemory()) { stackanalysis_printf("\t\t\tMemory read from: %s\n", operands[1].format(arch).c_str()); @@ -1778,7 +1815,13 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, // Case 1 stackanalysis_printf("\t\t\tCopy detected: %s -> %s\n", read.name().c_str(), written.name().c_str()); - xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); + if ((signed int) read.regClass() == x86::XMM || + (signed int) read.regClass() == x86_64::XMM) { + // Assume XMM registers only contain FP values, not pointers + xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); + } else { + xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); + } copyBaseSubReg(written, xferFuncs); } else { // Case 2 From 94403872a1707d4b605018afcf59d36f7a4fee2f Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Wed, 17 Aug 2016 09:40:53 -0500 Subject: [PATCH 024/180] Remove unnecessary assert from dwarfWalker. Fixes #152. --- symtabAPI/src/dwarfWalker.C | 1 - 1 file changed, 1 deletion(-) diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 453189fef7..2a4cce39aa 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -737,7 +737,6 @@ bool DwarfWalker::parseCommonBlock() { Symbol* commonBlockVar = findSymbolForCommonBlock(commonBlockName); if(!commonBlockVar) { - assert(!"No common block variables to parse!"); return false; } From dff30ae88e36c16cc646941bc5bd029cd4320d43 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Wed, 17 Aug 2016 14:05:17 -0500 Subject: [PATCH 025/180] Implement interprocedural analysis for StackMod. Sort the call graph topologically, and then generate function summaries in a bottom-up fashion, plugging in the summaries at call sites during StackAnalysis. --- dataflowAPI/h/stackanalysis.h | 45 +- dataflowAPI/src/stackanalysis.C | 712 +++++++++++++++++++++++--------- dyninstAPI/h/BPatch_function.h | 2 +- dyninstAPI/h/BPatch_object.h | 27 +- dyninstAPI/src/BPatch_object.C | 430 +++++++++++++++++++ dyninstAPI/src/function.C | 8 + 6 files changed, 1001 insertions(+), 223 deletions(-) diff --git a/dataflowAPI/h/stackanalysis.h b/dataflowAPI/h/stackanalysis.h index 2507c1a236..1604221451 100644 --- a/dataflowAPI/h/stackanalysis.h +++ b/dataflowAPI/h/stackanalysis.h @@ -148,14 +148,10 @@ class StackAnalysis { } static Height meet(std::set &ins) { - if (ins.empty()) { - return top; - } + if (ins.empty()) return top; // If there is a single element in the set return it. - if (ins.size() == 1) { - return *(ins.begin()); - } + if (ins.size() == 1) return *ins.begin(); // MEET (bottom, ...) == bottom // Since ins is sorted, if bottom is in the set it must @@ -164,7 +160,7 @@ class StackAnalysis { // MEET (N, top) == N if (ins.size() == 2 && *ins.rbegin() == top) { - return *(ins.begin()); + return *ins.begin(); } // There are 2 or more elements; the last one is not top; therefore @@ -230,6 +226,8 @@ class StackAnalysis { static TransferFunc meet(const TransferFunc &lhs, const TransferFunc &rhs); + bool isBaseRegCopy() const; + bool isBaseRegSIB() const; bool isIdentity() const; bool isBottom() const; bool isTop() const; @@ -306,6 +304,7 @@ class StackAnalysis { void validate() const; void add(TransferFuncs &f); + void addSummary(const TransferSet &summary); TransferSet accumFuncs; }; @@ -333,9 +332,16 @@ class StackAnalysis { // To avoid sucking enormous time, we keep those transfer functions around... typedef std::map > InstructionEffects; + typedef std::map> + CallEffects; DATAFLOW_EXPORT StackAnalysis(); DATAFLOW_EXPORT StackAnalysis(ParseAPI::Function *f); + // TODO: Update DataflowAPI manual + DATAFLOW_EXPORT StackAnalysis(ParseAPI::Function *f, + const std::map &crm, + const std::map &fs, + const std::set
&toppable = std::set
()); DATAFLOW_EXPORT Height find(ParseAPI::Block *, Address addr, Absloc loc); DATAFLOW_EXPORT Height findSP(ParseAPI::Block *, Address addr); @@ -344,6 +350,7 @@ class StackAnalysis { std::vector >& heights); // TODO: Update DataflowAPI manual + DATAFLOW_EXPORT bool canGetFunctionSummary(); DATAFLOW_EXPORT bool getFunctionSummary(TransferSet &summary); DATAFLOW_EXPORT void debug(); @@ -357,10 +364,10 @@ class StackAnalysis { bool analyze(); bool genInsnEffects(); - void summarizeBlocks(); + void summarizeBlocks(bool verbose = false); void summarize(); - void fixpoint(); + void fixpoint(bool verbose = false); void summaryFixpoint(); void createIntervals(); @@ -376,12 +383,15 @@ class StackAnalysis { AbslocState getSrcOutputLocs(ParseAPI::Edge* e); TransferSet getSummarySrcOutputLocs(ParseAPI::Edge *e); void computeInsnEffects(ParseAPI::Block *block, InstructionPtr insn, - const Offset off, TransferFuncs &xferFunc); + const Offset off, TransferFuncs &xferFunc, TransferSet &funcSummary); bool isCall(InstructionPtr insn); + bool isJump(InstructionPtr insn); bool handleNormalCall(InstructionPtr insn, ParseAPI::Block *block, - Offset off, TransferFuncs &xferFuncs); + Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary); bool handleThunkCall(InstructionPtr insn, TransferFuncs &xferFuncs); + bool handleJump(InstructionPtr insn, ParseAPI::Block *block, + Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary); void handlePushPop(InstructionPtr insn, ParseAPI::Block *block, const Offset off, int sign, TransferFuncs &xferFuncs); void handleReturn(InstructionPtr insn, TransferFuncs &xferFuncs); @@ -421,9 +431,22 @@ class StackAnalysis { ParseAPI::Function *func; + // Map from call sites to PLT-resolved addresses + std::map callResolutionMap; + + // Function summaries to utilize during analysis + std::map functionSummaries; + + // Functions whose return values should be topped rather than bottomed. This + // is used when evaluating a cycle in the call graph via fixed-point + // analysis. Note that if functionSummaries contains a summary for the + // function, it will be used instead. + std::set
toppableFunctions; + // SP effect tracking BlockEffects *blockEffects; // Pointer so we can make it an annotation InstructionEffects *insnEffects; // Pointer so we can make it an annotation + CallEffects *callEffects; // Pointer so we can make it an annotation BlockState blockInputs; BlockState blockOutputs; diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 4ab2ce1107..43285b259a 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -32,6 +32,7 @@ #include #include +#include #include #include "instructionAPI/h/BinaryFunction.h" @@ -65,6 +66,8 @@ AnnotationClass Stack_Anno_Block_Effects(std::string("Stack_Anno_Block_Effects")); AnnotationClass Stack_Anno_Insn_Effects(std::string("Stack_Anno_Insn_Effects")); +AnnotationClass + Stack_Anno_Call_Effects(std::string("Stack_Anno_Call_Effects")); template class std::list; template class std::map; @@ -92,7 +95,7 @@ bool StackAnalysis::analyze() { genInsnEffects(); stackanalysis_printf("\tPerforming fixpoint analysis\n"); - fixpoint(); + fixpoint(true); stackanalysis_printf("\tCreating SP interval tree\n"); summarize(); @@ -111,13 +114,19 @@ bool StackAnalysis::analyze() { bool StackAnalysis::genInsnEffects() { // Check if we've already done this work - if (blockEffects != NULL && insnEffects != NULL) return true; + if (blockEffects != NULL && insnEffects != NULL && callEffects != NULL) { + return true; + } func->getAnnotation(blockEffects, Stack_Anno_Block_Effects); func->getAnnotation(insnEffects, Stack_Anno_Insn_Effects); - if (blockEffects != NULL && insnEffects != NULL) return true; + func->getAnnotation(callEffects, Stack_Anno_Call_Effects); + if (blockEffects != NULL && insnEffects != NULL && callEffects != NULL) { + return true; + } blockEffects = new BlockEffects(); insnEffects = new InstructionEffects(); + callEffects = new CallEffects(); stackanalysis_printf("Beginning insn effect generation for function %s\n", func->name().c_str()); @@ -133,16 +142,18 @@ bool StackAnalysis::genInsnEffects() { // Clear mappings blockEffects->clear(); insnEffects->clear(); + callEffects->clear(); blockInputs.clear(); blockOutputs.clear(); // Generate final block effects with stack slot tracking stackanalysis_printf("\tGenerating final block effects\n"); - summarizeBlocks(); + summarizeBlocks(true); // Annotate insnEffects and blockEffects to avoid rework func->addAnnotation(blockEffects, Stack_Anno_Block_Effects); func->addAnnotation(insnEffects, Stack_Anno_Insn_Effects); + func->addAnnotation(callEffects, Stack_Anno_Call_Effects); stackanalysis_printf("Finished insn effect generation for function %s\n", func->name().c_str()); @@ -163,63 +174,90 @@ static void getInsnInstances(Block *block, InsnVec &insns) { } } +struct intra_nosink_nocatch : public ParseAPI::EdgePredicate { + virtual bool operator()(Edge* e) { + static Intraproc i; + static NoSinkPredicate n; + return i(e) && n(e) && e->type() != CATCH; + } +}; + +void add_target(std::queue& worklist, Edge* e) { + worklist.push(e->trg()); +} + +void add_target_exclude(std::stack &workstack, + std::set &excludeSet, Edge *e) { + Block *b = e->trg(); + if (excludeSet.find(b) == excludeSet.end()) { + excludeSet.insert(b); + workstack.push(b); + } +} + // We want to create a transfer function for the block as a whole. This will // allow us to perform our fixpoint calculation over blocks (thus, O(B^2)) // rather than instructions (thus, O(I^2)). -// -// Handling the stack height is straightforward. We also accumulate region -// changes in terms of a stack of Region objects. -void StackAnalysis::summarizeBlocks() { - Function::blocklist bs(func->blocks()); - for (auto bit = bs.begin(); bit != bs.end(); ++bit) { - Block *block = *bit; - // Accumulators. They have the following behavior: - // - // New region: add to the end of the regions list - // Offset to stack pointer: accumulate to delta. - // Setting the stack pointer: zero delta, set set_value. +void StackAnalysis::summarizeBlocks(bool verbose) { + intra_nosink_nocatch epred; + std::set doneSet; + std::stack workstack; + doneSet.insert(func->entry()); + workstack.push(func->entry()); + + while (!workstack.empty()) { + Block *block = workstack.top(); + workstack.pop(); SummaryFunc &bFunc = (*blockEffects)[block]; - stackanalysis_printf("\t Block starting at 0x%lx: %s\n", block->start(), - bFunc.format().c_str()); + if (verbose) { + stackanalysis_printf("\t Block starting at 0x%lx: %s\n", + block->start(), bFunc.format().c_str()); + } + InsnVec instances; getInsnInstances(block, instances); - for (unsigned j = 0; j < instances.size(); j++) { - InstructionAPI::Instruction::Ptr insn = instances[j].first; - Offset &off = instances[j].second; + const InstructionAPI::Instruction::Ptr insn = instances[j].first; + const Offset &off = instances[j].second; // Fills in insnEffects[off] TransferFuncs &xferFuncs = (*insnEffects)[block][off]; - computeInsnEffects(block, insn, off, xferFuncs); + TransferSet funcSummary; + computeInsnEffects(block, insn, off, xferFuncs, funcSummary); bFunc.add(xferFuncs); + if (!funcSummary.empty()) { + (*callEffects)[block][off] = funcSummary; + bFunc.addSummary(funcSummary); + } - stackanalysis_printf("\t\t\t At 0x%lx: %s\n", off, - bFunc.format().c_str()); + if (verbose) { + stackanalysis_printf("\t\t\t At 0x%lx: %s\n", off, + bFunc.format().c_str()); + } } - stackanalysis_printf("\t Block summary for 0x%lx: %s\n", block->start(), - bFunc.format().c_str()); - } -} -struct intra_nosink_nocatch : public ParseAPI::EdgePredicate { - virtual bool operator()(Edge* e) { - static Intraproc i; - static NoSinkPredicate n; - return i(e) && n(e) && e->type() != CATCH; - } -}; + if (verbose) { + stackanalysis_printf("\t Block summary for 0x%lx: %s\n", + block->start(), bFunc.format().c_str()); + } -void add_target(std::queue& worklist, Edge* e) { - worklist.push(e->trg()); + // Add blocks reachable from this one to the work stack + const Block::edgelist &targs = block->targets(); + std::for_each( + boost::make_filter_iterator(epred, targs.begin(), targs.end()), + boost::make_filter_iterator(epred, targs.end(), targs.end()), + boost::bind(add_target_exclude, boost::ref(workstack), + boost::ref(doneSet), _1) + ); + } } -void StackAnalysis::fixpoint() { +void StackAnalysis::fixpoint(bool verbose) { intra_nosink_nocatch epred2; - std::queue worklist; worklist.push(func->entry()); @@ -227,40 +265,57 @@ void StackAnalysis::fixpoint() { while (!worklist.empty()) { Block *block = worklist.front(); worklist.pop(); - stackanalysis_printf("\t Fixpoint analysis: visiting block at 0x%lx\n", - block->start()); + + if (verbose) { + stackanalysis_printf("\t Fixpoint analysis: visiting block at 0x%lx\n", + block->start()); + } // Step 1: calculate the meet over the heights of all incoming // intraprocedural blocks. AbslocState input; if (firstBlock) { createEntryInput(input); - stackanalysis_printf("\t Primed initial block\n"); + if (verbose) { + stackanalysis_printf("\t Primed initial block\n"); + } } else { - stackanalysis_printf("\t Calculating meet with block [%x-%x]\n", - block->start(), block->lastInsnAddr()); + if (verbose) { + stackanalysis_printf("\t Calculating meet with block [%x-%x]\n", + block->start(), block->lastInsnAddr()); + } meetInputs(block, blockInputs[block], input); } - stackanalysis_printf("\t New in meet: %s\n", format(input).c_str()); + + if (verbose) { + stackanalysis_printf("\t New in meet: %s\n", format(input).c_str()); + } // Step 2: see if the input has changed if (input == blockInputs[block]) { // No new work here - stackanalysis_printf("\t ... equal to current, skipping block\n"); + if (verbose) { + stackanalysis_printf("\t ... equal to current, skipping block\n"); + } continue; } - stackanalysis_printf("\t ... inequal to current %s, analyzing block\n", - format(blockInputs[block]).c_str()); + + if (verbose) { + stackanalysis_printf("\t ... inequal to current %s, analyzing block\n", + format(blockInputs[block]).c_str()); + } blockInputs[block] = input; // Step 3: calculate our new outs (*blockEffects)[block].apply(input, blockOutputs[block]); - stackanalysis_printf("\t ... output from block: %s\n", - format(blockOutputs[block]).c_str()); + if (verbose) { + stackanalysis_printf("\t ... output from block: %s\n", + format(blockOutputs[block]).c_str()); + } // Step 4: push all children on the worklist. - const Block::edgelist & outEdges = block->targets(); + const Block::edgelist &outEdges = block->targets(); std::for_each( boost::make_filter_iterator(epred2, outEdges.begin(), outEdges.end()), boost::make_filter_iterator(epred2, outEdges.end(), outEdges.end()), @@ -272,14 +327,62 @@ void StackAnalysis::fixpoint() { } +namespace { +void getRetAndTailCallBlocks(Function *func, std::set &retBlocks) { + retBlocks.clear(); + intra_nosink_nocatch epred; + std::set doneSet; + std::stack workstack; + doneSet.insert(func->entry()); + workstack.push(func->entry()); + + while (!workstack.empty()) { + Block *currBlock = workstack.top(); + workstack.pop(); + + const Block::edgelist &targs = currBlock->targets(); + for (auto iter = targs.begin(); iter != targs.end(); iter++) { + Edge *currEdge = *iter; + if (currEdge->type() == RET || + (currEdge->interproc() && currEdge->type() == DIRECT)) { + retBlocks.insert(currEdge->src()); + } + } + + std::for_each( + boost::make_filter_iterator(epred, targs.begin(), targs.end()), + boost::make_filter_iterator(epred, targs.end(), targs.end()), + boost::bind(add_target_exclude, boost::ref(workstack), + boost::ref(doneSet), _1) + ); + } +} +}; // namespace + + +// Looks for return edges in the function, following tail calls if necessary. +// Returns true if any return edges are found. +bool StackAnalysis::canGetFunctionSummary() { + std::set retBlocks; + getRetAndTailCallBlocks(func, retBlocks); + return !retBlocks.empty(); +} + + bool StackAnalysis::getFunctionSummary(TransferSet &summary) { df_init_debug(); + genInsnEffects(); + + if (!canGetFunctionSummary()) { + stackanalysis_printf("Cannot generate function summary for %s\n", + func->name().c_str()); + return false; + } - if (!genInsnEffects()) return false; assert(!blockEffects->empty()); - const Function::const_blocklist &retBlocks = func->returnBlocks(); - if (retBlocks.empty()) return false; // No return edges means no summary + stackanalysis_printf("Generating function summary for %s\n", + func->name().c_str()); if (blockSummaryOutputs.empty()) { summaryFixpoint(); @@ -287,21 +390,40 @@ bool StackAnalysis::getFunctionSummary(TransferSet &summary) { // Join possible values at all return edges TransferSet tempSummary; + std::set retBlocks; + getRetAndTailCallBlocks(func, retBlocks); + assert(!retBlocks.empty()); for (auto iter = retBlocks.begin(); iter != retBlocks.end(); iter++) { Block *currBlock = *iter; meetSummary(blockSummaryOutputs[currBlock], tempSummary); } - // Remove identity functions for simplicity + // Remove identity functions for simplicity. Also remove stack slots, except + // for stack slots in the caller's frame. Remove copies from base regs to + // subregs when the base regs are identities since the link between base reg + // and subreg will be made in the caller. summary.clear(); for (auto iter = tempSummary.begin(); iter != tempSummary.end(); iter++) { const Absloc &loc = iter->first; const TransferFunc &tf = iter->second; - if (!tf.isIdentity()) { - summary[loc] = tf; + if (!tf.isIdentity() && (tf.target.type() != Absloc::Stack || + tf.target.off() >= 0)) { + if (!tf.isBaseRegCopy() && !tf.isBaseRegSIB()) { + summary[loc] = tf; + } else { + const MachRegister &baseReg = tf.target.reg().getBaseRegister(); + const Absloc baseLoc(baseReg); + if (tempSummary.find(baseLoc) != tempSummary.end() && + !tempSummary[baseLoc].isIdentity()) { + summary[loc] = tf; + } + } } } + stackanalysis_printf("Finished function summary for %s:\n%s\n", + func->name().c_str(), format(summary).c_str()); + return true; } @@ -316,40 +438,29 @@ void StackAnalysis::summaryFixpoint() { while (!worklist.empty()) { Block *block = worklist.front(); worklist.pop(); - stackanalysis_printf("\tSummary fixpoint analysis: visiting block at " - "0x%lx\n", block->start()); // Step 1: calculate the meet over the heights of all incoming // intraprocedural blocks. TransferSet input; if (firstBlock) { createSummaryEntryInput(input); - stackanalysis_printf("\t Primed initial block\n"); } else { - stackanalysis_printf("\t Calculating meet with block [%x-%x]\n", - block->start(), block->lastInsnAddr()); meetSummaryInputs(block, blockSummaryInputs[block], input); } - stackanalysis_printf("\t New in meet: %s\n", format(input).c_str()); // Step 2: see if the input has changed if (input == blockSummaryInputs[block] && !firstBlock) { // No new work here - stackanalysis_printf("\t ... equal to current, skipping block\n"); continue; } - stackanalysis_printf("\t ... inequal to current %s, analyzing block\n", - format(blockSummaryInputs[block]).c_str()); blockSummaryInputs[block] = input; // Step 3: calculate our new outs (*blockEffects)[block].accumulate(input, blockSummaryOutputs[block]); - stackanalysis_printf("\t ... output from block: %s\n", - format(blockSummaryOutputs[block]).c_str()); // Step 4: push all children on the worklist. - const Block::edgelist & outEdges = block->targets(); + const Block::edgelist &outEdges = block->targets(); std::for_each( boost::make_filter_iterator(epred2, outEdges.begin(), outEdges.end()), boost::make_filter_iterator(epred2, outEdges.end(), outEdges.end()), @@ -387,6 +498,23 @@ void StackAnalysis::summarize() { input.erase(iter2->target); } } + + if (callEffects->find(block) != callEffects->end() && + (*callEffects)[block].find(off) != (*callEffects)[block].end()) { + // We have a function summary to apply + const TransferSet &summary = (*callEffects)[block][off]; + AbslocState newInput = input; + for (auto summaryIter = summary.begin(); + summaryIter != summary.end(); summaryIter++) { + const Absloc &target = summaryIter->first; + const TransferFunc &tf = summaryIter->second; + newInput[target] = tf.apply(input); + if (newInput[target].isTop()) { + newInput.erase(target); + } + } + input = newInput; + } } (*intervals_)[block][block->end()] = input; assert(input == blockOutputs[block]); @@ -394,8 +522,8 @@ void StackAnalysis::summarize() { } void StackAnalysis::computeInsnEffects(ParseAPI::Block *block, - Instruction::Ptr insn, const Offset off, TransferFuncs &xferFuncs) { - stackanalysis_printf("\t\tInsn at 0x%lx\n", off); + Instruction::Ptr insn, const Offset off, TransferFuncs &xferFuncs, + TransferSet &funcSummary) { entryID what = insn->getOperation().getID(); // Reminder: what we're interested in: @@ -419,11 +547,16 @@ void StackAnalysis::computeInsnEffects(ParseAPI::Block *block, // Cases we handle if (isCall(insn)) { - if (handleNormalCall(insn, block, off, xferFuncs)) return; + if (handleNormalCall(insn, block, off, xferFuncs, funcSummary)) return; else if (handleThunkCall(insn, xferFuncs)) return; else return handleDefault(insn, block, off, xferFuncs); } + if (isJump(insn)) { + handleJump(insn, block, off, xferFuncs, funcSummary); + return; + } + int sign = 1; switch (what) { case e_push: @@ -552,10 +685,10 @@ StackAnalysis::Height StackAnalysis::getStackCleanAmount(Function *func) { } StackAnalysis::StackAnalysis() : func(NULL), blockEffects(NULL), - insnEffects(NULL), intervals_(NULL), word_size(0) {} + insnEffects(NULL), callEffects(NULL), intervals_(NULL), word_size(0) {} StackAnalysis::StackAnalysis(Function *f) : func(f), blockEffects(NULL), - insnEffects(NULL), intervals_(NULL) { + insnEffects(NULL), callEffects(NULL), intervals_(NULL) { word_size = func->isrc()->getAddressWidth(); theStackPtr = Expression::Ptr(new RegisterAST(MachRegister::getStackPointer( func->isrc()->getArch()))); @@ -563,6 +696,20 @@ StackAnalysis::StackAnalysis(Function *f) : func(f), blockEffects(NULL), func->isrc()->getArch()))); } +StackAnalysis::StackAnalysis(Function *f, const std::map &crm, + const std::map &fs, + const std::set
&toppable) : + func(f), callResolutionMap(crm), functionSummaries(fs), + toppableFunctions(toppable), blockEffects(NULL), insnEffects(NULL), + callEffects(NULL), intervals_(NULL) { + word_size = func->isrc()->getAddressWidth(); + theStackPtr = Expression::Ptr(new RegisterAST(MachRegister::getStackPointer( + func->isrc()->getArch()))); + thePC = Expression::Ptr(new RegisterAST(MachRegister::getPC( + func->isrc()->getArch()))); +} + + void StackAnalysis::debug() { } @@ -641,9 +788,6 @@ void StackAnalysis::findDefinedHeights(ParseAPI::Block* b, Address addr, i != (*intervals_)[b][addr].end(); ++i) { if (i->second.isTop()) continue; - stackanalysis_printf("\t\tAdding %s:%s to defined heights at 0x%lx\n", - i->first.format().c_str(), i->second.format().c_str(), addr); - heights.push_back(*i); } } @@ -950,7 +1094,6 @@ void StackAnalysis::handleXor(Instruction::Ptr insn, Block *block, void StackAnalysis::handleDiv(Instruction::Ptr insn, TransferFuncs &xferFuncs) { - stackanalysis_printf("\t\t\thandleDiv: %s\n", insn->format().c_str()); std::vector operands; insn->getOperands(operands); assert(operands.size() == 3); @@ -1046,22 +1189,14 @@ void StackAnalysis::handleMul(Instruction::Ptr insn, void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, const Offset off, int sign, TransferFuncs &xferFuncs) { - long delta = 0; Operand arg = insn->getOperand(0); // Why was this here? bernat, 12JAN11 if (arg.getValue()->eval().defined) { delta = sign * word_size; - stackanalysis_printf( - "\t\t\t Stack height changed by evaluated push/pop: %lx\n", delta); } else { delta = sign * arg.getValue()->size(); - //cerr << "Odd case: set delta to " << hex << delta << dec << - // " for instruction " << insn->format() << endl; - stackanalysis_printf( - "\t\t\t Stack height changed by unevalled push/pop: %lx\n", delta); } - // delta = sign *arg.getValue()->size(); xferFuncs.push_back(TransferFunc::deltaFunc(Absloc(sp()), delta)); copyBaseSubReg(sp(), xferFuncs); @@ -1155,7 +1290,6 @@ void StackAnalysis::handleReturn(Instruction::Ptr insn, } } */ - stackanalysis_printf("\t\t\t Stack height changed by return: %lx\n", delta); xferFuncs.push_back(TransferFunc::deltaFunc(Absloc(sp()), delta)); copyBaseSubReg(sp(), xferFuncs); } @@ -1190,9 +1324,6 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, // a. If it can, mem1 is handled with a delta. // b. Otherwise, nothing happens. - stackanalysis_printf("\t\t\t handleAddSub, insn = %s\n", - insn->format().c_str()); - Architecture arch = insn->getArch(); // Needed for debug messages std::vector operands; insn->getOperands(operands); assert(operands.size() == 2); @@ -1205,8 +1336,6 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, if (insn->writesMemory()) { // Cases 3 and 5 assert(writeSet.size() == 0); - stackanalysis_printf("\t\t\tMemory add/sub to: %s\n", - operands[0].format(arch).c_str()); // Extract the expression inside the dereference std::vector addrExpr; @@ -1231,11 +1360,8 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, // We have a static address writtenLoc = Absloc(resultPair.first); } - stackanalysis_printf("\t\t\tEvaluates to: %s\n", - writtenLoc.format().c_str()); } else { // Cases 3b and 5b - stackanalysis_printf("\t\t\tCan't determine location\n"); return; } @@ -1281,9 +1407,6 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, if (insn->readsMemory()) { // Case 2 - stackanalysis_printf("\t\t\tAdd/sub from: %s\n", - operands[1].format(arch).c_str()); - // Extract the expression inside the dereference std::vector addrExpr; operands[1].getValue()->getChildren(addrExpr); @@ -1308,8 +1431,6 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, // We have a static address readLoc = Absloc(resultPair.first); } - stackanalysis_printf("\t\t\tEvaluates to: %s\n", - readLoc.format().c_str()); std::map> terms; terms[readLoc] = make_pair(sign, false); terms[writtenLoc] = make_pair(1, false); @@ -1317,7 +1438,6 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, copyBaseSubReg(written, xferFuncs); } else { // Case 2b - stackanalysis_printf("\t\t\tCan't determine location\n"); xferFuncs.push_back(TransferFunc::copyFunc(writtenLoc, writtenLoc, true)); copyBaseSubReg(written, xferFuncs); @@ -1329,7 +1449,6 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, if (res.defined) { // Case 4 long delta = sign * extractDelta(res); - stackanalysis_printf("\t\t\t Register changed by add/sub: %lx\n", delta); xferFuncs.push_back(TransferFunc::deltaFunc(writtenLoc, delta)); copyBaseSubReg(written, xferFuncs); } else { @@ -1368,10 +1487,7 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, // op1: reg // or // op1: imm - - stackanalysis_printf("\t\t\t handleLEA, insn = %s\n", - insn->format().c_str()); - + // std::set readSet; std::set writtenSet; insn->getOperand(0).getWriteSet(writtenSet); @@ -1386,9 +1502,6 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, std::vector children; srcExpr->getChildren(children); - stackanalysis_printf("\t\t\t\t srcOperand = %s\n", - srcExpr->format().c_str()); - if (readSet.size() == 0) { // op1: imm assert(typeid(*srcExpr) == typeid(Immediate)); @@ -1419,10 +1532,6 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, // op1: reg + imm regExpr = children[0]; deltaExpr = children[1]; - stackanalysis_printf("\t\t\t\t reg: %s\n", - regExpr->format().c_str()); - stackanalysis_printf("\t\t\t\t delta: %s\n", - deltaExpr->format().c_str()); assert(typeid(*regExpr) == typeid(RegisterAST)); assert(typeid(*deltaExpr) == typeid(Immediate)); foundDelta = true; @@ -1471,8 +1580,6 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, // op1: reg + reg * imm + imm // Extract the delta and continue on to get base, index, and scale deltaExpr = children[1]; - stackanalysis_printf("\t\t\t\t delta: %s\n", - deltaExpr->format().c_str()); Expression::Ptr sibExpr = children[0]; assert(typeid(*sibExpr) == typeid(BinaryFunction)); children.clear(); @@ -1484,7 +1591,6 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, // op1: reg + reg * imm baseExpr = children[0]; Expression::Ptr scaleIndexExpr = children[1]; - stackanalysis_printf("\t\t\t\t base: %s\n", baseExpr->format().c_str()); assert(typeid(*scaleIndexExpr) == typeid(BinaryFunction)); // Extract the index and scale @@ -1493,10 +1599,6 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, assert(children.size() == 2); indexExpr = children[0]; scaleExpr = children[1]; - stackanalysis_printf("\t\t\t\t index: %s\n", - indexExpr->format().c_str()); - stackanalysis_printf("\t\t\t\t scale: %s\n", - scaleExpr->format().c_str()); assert(typeid(*baseExpr) == typeid(RegisterAST)); assert(typeid(*indexExpr) == typeid(RegisterAST)); @@ -1543,14 +1645,14 @@ void StackAnalysis::handleLeave(Block *block, const Offset off, xferFuncs.push_back(TransferFunc::copyFunc(Absloc(fp()), Absloc(sp()))); copyBaseSubReg(fp(), xferFuncs); - // pop ebp: adjust stack pointer - xferFuncs.push_back(TransferFunc::deltaFunc(Absloc(sp()), word_size)); - copyBaseSubReg(sp(), xferFuncs); - // pop ebp: copy value from stack to ebp Absloc targLoc(fp()); if (intervals_ != NULL) { - Absloc sploc(sp()); + // Note that the stack pointer after the copy recorded above is now the + // same as the frame pointer at the start of this instruction. Thus, we + // use the height of the frame pointer at the start of this instruction to + // track the memory location read by the pop. + Absloc sploc(fp()); Height spHeight = (*intervals_)[block][off][sploc]; if (spHeight.isTop()) { // Load from a topped location. Since StackMod fails when storing @@ -1573,6 +1675,10 @@ void StackAnalysis::handleLeave(Block *block, const Offset off, xferFuncs.push_back(TransferFunc::bottomFunc(targLoc)); bottomBaseSubReg(fp(), xferFuncs); } + + // pop ebp: adjust stack pointer + xferFuncs.push_back(TransferFunc::deltaFunc(Absloc(sp()), word_size)); + copyBaseSubReg(sp(), xferFuncs); } void StackAnalysis::handlePushPopFlags(int sign, TransferFuncs &xferFuncs) { @@ -1604,14 +1710,9 @@ void StackAnalysis::handlePowerAddSub(Instruction::Ptr insn, Block *block, xferFuncs.push_back(TransferFunc::deltaFunc(sploc, sign * res.convert())); copyBaseSubReg(sp(), xferFuncs); - stackanalysis_printf( - "\t\t\t Stack height changed by evalled add/sub: %lx\n", - sign * res.convert()); } else { xferFuncs.push_back(TransferFunc::bottomFunc(sploc)); bottomBaseSubReg(sp(), xferFuncs); - stackanalysis_printf( - "\t\t\t Stack height changed by unevalled add/sub: bottom\n"); } } @@ -1624,10 +1725,6 @@ void StackAnalysis::handlePowerStoreUpdate(Instruction::Ptr insn, Block *block, std::set memWriteAddrs; insn->getMemoryWriteOperands(memWriteAddrs); Expression::Ptr stackWrite = *(memWriteAddrs.begin()); - stackanalysis_printf("\t\t\t ...checking operand %s\n", - stackWrite->format().c_str()); - stackanalysis_printf("\t\t\t ...binding %s to 0\n", - theStackPtr->format().c_str()); stackWrite->bind(theStackPtr.get(), Result(u32, 0)); Result res = stackWrite->eval(); Absloc sploc(sp()); @@ -1635,13 +1732,9 @@ void StackAnalysis::handlePowerStoreUpdate(Instruction::Ptr insn, Block *block, long delta = res.convert(); xferFuncs.push_back(TransferFunc::deltaFunc(sploc, delta)); copyBaseSubReg(sp(), xferFuncs); - stackanalysis_printf( - "\t\t\t Stack height changed by evalled stwu: %lx\n", delta); } else { xferFuncs.push_back(TransferFunc::bottomFunc(sploc)); bottomBaseSubReg(sp(), xferFuncs); - stackanalysis_printf( - "\t\t\t Stack height changed by unevalled stwu: bottom\n"); } } @@ -1673,8 +1766,6 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, // a. If it can, we give the address an absolute value. // b. Otherwise, we ignore the store. - Architecture arch = insn->getArch(); // Needed for debug messages - // Extract operands std::vector operands; insn->getOperands(operands); @@ -1689,8 +1780,6 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, if (insn->writesMemory()) { assert(writtenRegs.size() == 0); - stackanalysis_printf("\t\t\tMemory write to: %s\n", - operands[0].format(arch).c_str()); // Extract the expression inside the dereference std::vector addrExpr; @@ -1715,11 +1804,8 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, // We have a static address writtenLoc = Absloc(resultPair.first); } - stackanalysis_printf("\t\t\tEvaluates to: %s\n", - writtenLoc.format().c_str()); } else { // Cases 4b and 5b - stackanalysis_printf("\t\t\tCan't determine location\n"); return; } @@ -1760,9 +1846,6 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, } if (insn->readsMemory()) { - stackanalysis_printf("\t\t\tMemory read from: %s\n", - operands[1].format(arch).c_str()); - // Extract the expression inside the dereference std::vector addrExpr; operands[1].getValue()->getChildren(addrExpr); @@ -1787,13 +1870,10 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, // We have a static address readLoc = Absloc(resultPair.first); } - stackanalysis_printf("\t\t\tEvaluates to: %s\n", - readLoc.format().c_str()); xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); copyBaseSubReg(written, xferFuncs); } else { // Case 3b - stackanalysis_printf("\t\t\tCan't determine location\n"); xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); retopBaseSubReg(written, xferFuncs); } @@ -1813,8 +1893,6 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, if (read.isValid()) { // Case 1 - stackanalysis_printf("\t\t\tCopy detected: %s -> %s\n", - read.name().c_str(), written.name().c_str()); if ((signed int) read.regClass() == x86::XMM || (signed int) read.regClass() == x86_64::XMM) { // Assume XMM registers only contain FP values, not pointers @@ -1828,8 +1906,6 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, InstructionAPI::Expression::Ptr readExpr = operands[1].getValue(); assert(typeid(*readExpr) == typeid(InstructionAPI::Immediate)); long readValue = readExpr->eval().convert(); - stackanalysis_printf("\t\t\tImmediate to register move: %s set to %ld\n", - written.name().c_str(), readValue); xferFuncs.push_back(TransferFunc::absFunc(writtenLoc, readValue)); retopBaseSubReg(written, xferFuncs); } @@ -1840,8 +1916,6 @@ void StackAnalysis::handleZeroExtend(Instruction::Ptr insn, Block *block, // In x86/x86_64, zero extends can't write to memory assert(!insn->writesMemory()); - Architecture arch = insn->getArch(); // Needed for debug messages - // Extract operands std::vector operands; insn->getOperands(operands); @@ -1859,9 +1933,6 @@ void StackAnalysis::handleZeroExtend(Instruction::Ptr insn, Block *block, // Handle memory loads if (insn->readsMemory()) { - stackanalysis_printf("\t\t\tMemory read from: %s\n", - operands[1].format(arch).c_str()); - // Extract the expression inside the dereference std::vector addrExpr; operands[1].getValue()->getChildren(addrExpr); @@ -1886,13 +1957,10 @@ void StackAnalysis::handleZeroExtend(Instruction::Ptr insn, Block *block, // We have a static address readLoc = Absloc(resultPair.first); } - stackanalysis_printf("\t\t\tEvaluates to: %s\n", - readLoc.format().c_str()); xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); copyBaseSubReg(written, xferFuncs); } else { // We can't track this memory location - stackanalysis_printf("\t\t\tCan't determine location\n"); xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); retopBaseSubReg(written, xferFuncs); } @@ -1902,8 +1970,6 @@ void StackAnalysis::handleZeroExtend(Instruction::Ptr insn, Block *block, assert(readRegs.size() == 1); Absloc readLoc((*readRegs.begin())->getID()); - stackanalysis_printf("\t\t\tCopy detected: %s -> %s\n", - readLoc.format().c_str(), writtenLoc.format().c_str()); xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); copyBaseSubReg(written, xferFuncs); } @@ -1917,8 +1983,6 @@ void StackAnalysis::handleSignExtend(Instruction::Ptr insn, Block *block, // In x86/x86_64, sign extends can't write to memory assert(!insn->writesMemory()); - Architecture arch = insn->getArch(); // Needed for debug messages - // Extract operands std::vector operands; insn->getOperands(operands); @@ -1936,9 +2000,6 @@ void StackAnalysis::handleSignExtend(Instruction::Ptr insn, Block *block, // Handle memory loads if (insn->readsMemory()) { - stackanalysis_printf("\t\t\tMemory read from: %s\n", - operands[1].format(arch).c_str()); - // Extract the expression inside the dereference std::vector addrExpr; operands[1].getValue()->getChildren(addrExpr); @@ -1963,14 +2024,11 @@ void StackAnalysis::handleSignExtend(Instruction::Ptr insn, Block *block, // We have a static address readLoc = Absloc(resultPair.first); } - stackanalysis_printf("\t\t\tEvaluates to: %s\n", - readLoc.format().c_str()); xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc, true)); copyBaseSubReg(written, xferFuncs); } else { // We can't track this memory location - stackanalysis_printf("\t\t\tCan't determine location\n"); xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); retopBaseSubReg(written, xferFuncs); } @@ -1980,9 +2038,6 @@ void StackAnalysis::handleSignExtend(Instruction::Ptr insn, Block *block, assert(readRegs.size() == 1); Absloc readLoc((*readRegs.begin())->getID()); - stackanalysis_printf( - "\t\t\t Sign extend insn detected: %s -> %s (must be top or bottom)\n", - readLoc.format().c_str(), writtenLoc.format().c_str()); xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc, true)); copyBaseSubReg(written, xferFuncs); } @@ -2009,9 +2064,6 @@ void StackAnalysis::handleSpecialSignExtend(Instruction::Ptr insn, Absloc writtenLoc(writtenReg); Absloc readLoc(readReg); - stackanalysis_printf( - "\t\t\t Special sign extend detected: %s -> %s (must be top/bottom)\n", - readLoc.format().c_str(), writtenLoc.format().c_str()); xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc, true)); copyBaseSubReg(writtenReg, xferFuncs); } @@ -2112,6 +2164,12 @@ void StackAnalysis::handleDefault(Instruction::Ptr insn, Block *block, } continue; } + if (writtenLoc.type() == Absloc::Register && + writtenLoc.reg().size() < 4) { + // Assume registers smaller than 4 bytes are not used to hold pointers + xferFuncs.push_back(TransferFunc::retopFunc(writtenLoc)); + continue; + } std::map> fromRegs; for (auto rIter = readLocs.begin(); rIter != readLocs.end(); rIter++) { const Absloc &readLoc = *rIter; @@ -2128,14 +2186,102 @@ bool StackAnalysis::isCall(Instruction::Ptr insn) { return insn->getCategory() == c_CallInsn; } +bool StackAnalysis::isJump(Instruction::Ptr insn) { + return insn->getCategory() == c_BranchInsn; +} + bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, - Offset off, TransferFuncs &xferFuncs) { + Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary) { if (!insn->getControlFlowTarget()) return false; // Must be a thunk based on parsing. if (off != block->lastInsnAddr()) return false; - + + Address calledAddr = 0; + const Block::edgelist &outs = block->targets(); + for (auto eit = outs.begin(); eit != outs.end(); eit++) { + Edge *edge = *eit; + if (edge->type() != CALL) continue; + + if (callResolutionMap.find(off) != callResolutionMap.end()) { + // This call has already been resolved with PLT info available, so we + // should use that resolution information. + calledAddr = callResolutionMap[off]; + } else { + // This call has not been resolved yet. + Block *calledBlock = edge->trg(); + calledAddr = calledBlock->start(); + } + if (intervals_ != NULL && + functionSummaries.find(calledAddr) != functionSummaries.end()) { + stackanalysis_printf("\t\t\tFound function summary for %lx\n", + calledAddr); + xferFuncs.push_back(TransferFunc::deltaFunc(Absloc(sp()), -word_size)); + copyBaseSubReg(sp(), xferFuncs); + + // Update stack slots in the summary to line up with this stack frame, + // and then add the modified transfer functions to xferFuncs. + Height spHeight = (*intervals_)[block][off][Absloc(sp())]; + const TransferSet &fs = functionSummaries[calledAddr]; + for (auto fsIter = fs.begin(); fsIter != fs.end(); fsIter++) { + Absloc summaryLoc = fsIter->first; + TransferFunc tf = fsIter->second; + if (tf.from.type() == Absloc::Stack) { + if (spHeight.isBottom() || tf.from.off() < 0) { + // Copying from unknown stack slot. Bottom the target. + tf = TransferFunc::bottomFunc(tf.target); + } else if (spHeight.isTop()) { + // Copying from unknown non-stack location. Top the target. + tf = TransferFunc::retopFunc(tf.target); + } else { + int newOff = tf.from.off() + (int) spHeight.height(); + tf.from = Absloc(newOff, 0, NULL); + } + } + if (tf.target.type() == Absloc::Stack) { + // Ignore writes to unresolvable locations + if (spHeight.isBottom() || spHeight.isTop()) continue; + + if (tf.target.off() < 0) { + fprintf(stderr, "Function summary writes to own frame\n"); + fprintf(stderr, "%s\n", tf.format().c_str()); + assert(false); + } + int newOff = tf.target.off() + (int) spHeight.height(); + tf.target = Absloc(newOff, 0, NULL); + summaryLoc = tf.target; + } + std::map> newFromRegs; + for (auto frIter = tf.fromRegs.begin(); frIter != tf.fromRegs.end(); + frIter++) { + const Absloc &loc = frIter->first; + const std::pair &pair = frIter->second; + if (loc.type() == Absloc::Stack) { + if (spHeight.isBottom() || loc.off() < 0) { + // fromRegs contains an unresolvable stack slot. Bottom + // the target. + tf = TransferFunc::bottomFunc(tf.target); + break; + } + // Ignore topped locations + if (spHeight.isTop()) continue; + + int newOff = loc.off() + (int) spHeight.height(); + newFromRegs[Absloc(newOff, 0, NULL)] = pair; + } else { + newFromRegs[loc] = pair; + } + } + if (!tf.isBottom()) tf.fromRegs = newFromRegs; + + stackanalysis_printf("%s\n", tf.format().c_str()); + funcSummary[summaryLoc] = tf; + } + return true; + } + } + // Top caller-save registers // Bottom return registers ABI* abi = ABI::getABI(word_size); @@ -2167,8 +2313,10 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, if ((*iter).first.regClass() == gpr) { if (callWritten.test((*iter).second)) { Absloc loc((*iter).first); - if (returnRegs.test((*iter).second)) { - // Bottom + if (toppableFunctions.find(calledAddr) == toppableFunctions.end() && + returnRegs.test((*iter).second)) { + // Bottom return registers if the called function isn't marked as + // toppable. xferFuncs.push_back(TransferFunc::bottomFunc(loc)); bottomBaseSubReg(iter->first, xferFuncs); } else { @@ -2180,7 +2328,6 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, } } - const Block::edgelist &outs = block->targets(); for (auto eit = outs.begin(); eit != outs.end(); ++eit) { Edge *cur_edge = (Edge*)*eit; @@ -2190,8 +2337,6 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, // For some reason we're treating this // call as a branch. So it shifts the stack // like a push (heh) and then we're done. - stackanalysis_printf( - "\t\t\t Stack height changed by simulate-jump call\n"); xferFuncs.push_back(TransferFunc::deltaFunc(sploc, -1 * word_size)); copyBaseSubReg(sp(), xferFuncs); return true; @@ -2207,24 +2352,164 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, Height h = getStackCleanAmount(target_func); if (h == Height::bottom) { - stackanalysis_printf( - "\t\t\t Stack height changed by self-cleaning function: bottom\n"); xferFuncs.push_back(TransferFunc::bottomFunc(sploc)); bottomBaseSubReg(sp(), xferFuncs); } else { - stackanalysis_printf( - "\t\t\t Stack height changed by self-cleaning function: %ld\n", - h.height()); xferFuncs.push_back(TransferFunc::deltaFunc(sploc, h.height())); copyBaseSubReg(sp(), xferFuncs); } return true; + } + return true; +} +// Create transfer functions for tail calls +bool StackAnalysis::handleJump(Instruction::Ptr insn, Block *block, Offset off, + TransferFuncs &xferFuncs, TransferSet &funcSummary) { + Address calledAddr = 0; + const Block::edgelist &outs = block->targets(); + for (auto eit = outs.begin(); eit != outs.end(); eit++) { + Edge *edge = *eit; + if (!edge->interproc() || edge->type() != DIRECT) continue; + + if (callResolutionMap.find(off) != callResolutionMap.end()) { + // This tail call has already been resolved with PLT info available, so + // we should use that resolution information. + calledAddr = callResolutionMap[off]; + } else { + // This tail call has not been resolved yet. + Block *calledBlock = edge->trg(); + calledAddr = calledBlock->start(); + } + if (intervals_ != NULL && + functionSummaries.find(calledAddr) != functionSummaries.end()) { + stackanalysis_printf("\t\t\tFound function summary for %lx\n", + calledAddr); + + // Update stack slots in the summary to line up with this stack frame, + // and then add the modified transfer functions to xferFuncs. + Height spHeight = (*intervals_)[block][off][Absloc(sp())]; + const TransferSet &fs = functionSummaries[calledAddr]; + for (auto fsIter = fs.begin(); fsIter != fs.end(); fsIter++) { + Absloc summaryLoc = fsIter->first; + TransferFunc tf = fsIter->second; + if (tf.from.type() == Absloc::Stack) { + if (spHeight.isBottom() || tf.from.off() < 0) { + // Copying from unknown stack slot. Bottom the target. + tf = TransferFunc::bottomFunc(tf.target); + } else if (spHeight.isTop()) { + // Copying from unknown non-stack location. Top the target. + tf = TransferFunc::retopFunc(tf.target); + } else { + int newOff = tf.from.off() + (int) spHeight.height(); + tf.from = Absloc(newOff, 0, NULL); + } + } + if (tf.target.type() == Absloc::Stack) { + // Ignore writes to unresolvable locations + if (spHeight.isBottom() || spHeight.isTop()) continue; + + if (tf.target.off() < 0) { + fprintf(stderr, "Function summary writes to own frame\n"); + fprintf(stderr, "%s\n", tf.format().c_str()); + assert(false); + } + int newOff = tf.target.off() + (int) spHeight.height(); + tf.target = Absloc(newOff, 0, NULL); + summaryLoc = tf.target; + } + std::map> newFromRegs; + for (auto frIter = tf.fromRegs.begin(); frIter != tf.fromRegs.end(); + frIter++) { + const Absloc &loc = frIter->first; + const std::pair &pair = frIter->second; + if (loc.type() == Absloc::Stack) { + if (spHeight.isBottom() || loc.off() < 0) { + // fromRegs contains an unresolvable stack slot. Bottom + // the target. + tf = TransferFunc::bottomFunc(tf.target); + break; + } + // Ignore topped locations + if (spHeight.isTop()) continue; + + int newOff = loc.off() + (int) spHeight.height(); + newFromRegs[Absloc(newOff, 0, NULL)] = pair; + } else { + newFromRegs[loc] = pair; + } + } + if (!tf.isBottom()) tf.fromRegs = newFromRegs; + + stackanalysis_printf("%s\n", tf.format().c_str()); + funcSummary[summaryLoc] = tf; + } + return true; + } + } + + if (calledAddr == 0) { + // Not a tail call + return false; + } + + // This is a tail call, but we don't have a function summary for the called + // function. Therefore, we handle it as a call, followed by a return. + // + // i.e. jmp is equivalent to call ; ret + + // Top caller-save registers + // Bottom return registers + ABI* abi = ABI::getABI(word_size); + const bitArray callWritten = abi->getCallWrittenRegisters(); + const bitArray returnRegs = abi->getReturnRegisters(); + for (auto iter = abi->getIndexMap()->begin(); + iter != abi->getIndexMap()->end(); + ++iter) { + // We only care about GPRs right now + unsigned int gpr; + Architecture arch = insn->getArch(); + switch(arch) { + case Arch_x86: + gpr = x86::GPR; + break; + case Arch_x86_64: + gpr = x86_64::GPR; + break; + case Arch_ppc32: + gpr = ppc32::GPR; + break; + case Arch_ppc64: + gpr = ppc64::GPR; + break; + default: + handleDefault(insn, block, off, xferFuncs); + return true; + } + if ((*iter).first.regClass() == gpr) { + if (callWritten.test((*iter).second)) { + Absloc loc((*iter).first); + if (toppableFunctions.find(calledAddr) == toppableFunctions.end() && + returnRegs.test((*iter).second)) { + // Bottom return registers if the called function isn't marked as + // toppable. + xferFuncs.push_back(TransferFunc::bottomFunc(loc)); + bottomBaseSubReg(iter->first, xferFuncs); + } else { + // Top + xferFuncs.push_back(TransferFunc::retopFunc(loc)); + retopBaseSubReg(iter->first, xferFuncs); + } + } + } } - stackanalysis_printf("\t\t\t Stack height assumed unchanged by call\n"); + + // Adjust the stack pointer for the implicit return (see comment above). + xferFuncs.push_back(TransferFunc::deltaFunc(Absloc(sp()), word_size)); + copyBaseSubReg(sp(), xferFuncs); + return true; } - bool StackAnalysis::handleThunkCall(Instruction::Ptr insn, TransferFuncs &xferFuncs) { @@ -2309,17 +2594,12 @@ StackAnalysis::AbslocState StackAnalysis::getSrcOutputLocs(Edge* e) { StackAnalysis::TransferSet StackAnalysis::getSummarySrcOutputLocs(Edge* e) { Block* b = e->src(); - stackanalysis_printf("%lx ", b->lastInsnAddr()); return blockSummaryOutputs[b]; } void StackAnalysis::meetInputs(Block *block, AbslocState& blockInput, AbslocState &input) { - input.clear(); - - //Intraproc epred; // ignore calls, returns in edge iteration - //NoSinkPredicate epred2(&epred); // ignore sink node (unresolvable) intra_nosink_nocatch epred2; stackanalysis_printf("\t ... In edges: "); @@ -2338,14 +2618,9 @@ void StackAnalysis::meetInputs(Block *block, AbslocState& blockInput, void StackAnalysis::meetSummaryInputs(Block *block, TransferSet &blockInput, TransferSet &input) { - input.clear(); - - //Intraproc epred; // ignore calls, returns in edge iteration - //NoSinkPredicate epred2(&epred); // ignore sink node (unresolvable) intra_nosink_nocatch epred2; - stackanalysis_printf("\t ... In edges: "); const Block::edgelist & inEdges = block->sources(); std::for_each( boost::make_filter_iterator(epred2, inEdges.begin(), inEdges.end()), @@ -2353,11 +2628,11 @@ void StackAnalysis::meetSummaryInputs(Block *block, TransferSet &blockInput, boost::bind(&StackAnalysis::meetSummary, this, boost::bind(&StackAnalysis::getSummarySrcOutputLocs, this, _1), boost::ref(input))); - stackanalysis_printf("\n"); meetSummary(blockInput, input); } + void StackAnalysis::meet(const AbslocState &input, AbslocState &accum) { for (AbslocState::const_iterator iter = input.begin(); iter != input.end(); ++iter) { @@ -2585,6 +2860,20 @@ StackAnalysis::TransferFunc StackAnalysis::TransferFunc::meet( } +bool StackAnalysis::TransferFunc::isBaseRegCopy() const { + return isCopy() && !isTopBottom() && target.type() == Absloc::Register && + from.type() == Absloc::Register && target.reg().size() == 4 && + from.reg().size() == 8 && target.reg().getBaseRegister() == from.reg(); +} + +bool StackAnalysis::TransferFunc::isBaseRegSIB() const { + return isSIB() && fromRegs.size() == 2 && + target.type() == Absloc::Register && target.reg().size() == 4 && + target.reg().getBaseRegister().size() == 8 && + fromRegs.find(target) != fromRegs.end() && + fromRegs.find(Absloc(target.reg().getBaseRegister())) != fromRegs.end(); +} + bool StackAnalysis::TransferFunc::isIdentity() const { return isCopy() && from == target && delta == 0 && !topBottom; } @@ -3012,8 +3301,7 @@ void StackAnalysis::SummaryFunc::accumulate(const TransferSet &in, out = in; // Apply in parallel since all summary funcs are from the start of the block - for (TransferSet::const_iterator iter = accumFuncs.begin(); - iter != accumFuncs.end(); ++iter) { + for (auto iter = accumFuncs.begin(); iter != accumFuncs.end(); ++iter) { assert(iter->first.isValid()); out[iter->first] = iter->second.summaryAccumulate(in); if (out[iter->first].isTop() && !out[iter->first].isRetop()) { @@ -3032,6 +3320,18 @@ void StackAnalysis::SummaryFunc::add(TransferFuncs &xferFuncs) { validate(); } +void StackAnalysis::SummaryFunc::addSummary(const TransferSet &summary) { + // Accumulate all transfer functions in the summary atomically. + TransferSet newAccumFuncs = accumFuncs; + for (auto iter = summary.begin(); iter != summary.end(); ++iter) { + const Absloc &loc = iter->first; + const TransferFunc &func = iter->second; + newAccumFuncs[loc] = func.summaryAccumulate(accumFuncs); + } + accumFuncs = newAccumFuncs; + validate(); +} + void StackAnalysis::SummaryFunc::validate() const { for (TransferSet::const_iterator iter = accumFuncs.begin(); iter != accumFuncs.end(); ++iter) { diff --git a/dyninstAPI/h/BPatch_function.h b/dyninstAPI/h/BPatch_function.h index 2c8ad2a5bb..8259d794b4 100644 --- a/dyninstAPI/h/BPatch_function.h +++ b/dyninstAPI/h/BPatch_function.h @@ -340,7 +340,7 @@ class BPATCH_DLL_EXPORT BPatch_function : bool getAddressRange(void * &start, void * &end); - bool getAddressRange(Dyninst::Address &start, Dyninst::Address &end); + bool getAddressRange(Dyninst::Address &start, Dyninst::Address &end); unsigned int getFootprint(); BPatch_variableExpr *getFunctionRef(); diff --git a/dyninstAPI/h/BPatch_object.h b/dyninstAPI/h/BPatch_object.h index f674b1ef65..69c06a0e32 100644 --- a/dyninstAPI/h/BPatch_object.h +++ b/dyninstAPI/h/BPatch_object.h @@ -35,6 +35,7 @@ #include #include "dyntypes.h" #include "BPatch_dll.h" +#include "StackMod.h" class mapped_object; class BPatch_addressSpace; @@ -147,6 +148,27 @@ class BPATCH_DLL_EXPORT BPatch_object { // if there is not overlapping code. bool findPoints(Dyninst::Address addr, std::vector &points); + // BPatch_object::addModsAllProcs + // Apply stack modifications in mods to all functions in the current + // object. Perform error checking, handle stack alignment requirements, and + // generate any modifications required for cleanup at function exit. + // Atomically adds all modifications in mods; if any mod is found to be + // unsafe, none of the modifications are applied. If interproc is true, + // interprocedural analysis is used for more precise evaluation of + // modification safety (i.e. modifications that are actually safe are more + // likely to be correctly identified as safe, but analysis will take + // longer). depthLimit specifies the maximum depth allowed for + // interprocedural analysis, and is only used if interproc is true. Note + // that depthLimit 0 will still analyze interprocedural edges within the + // current object; it just won't analyze edges between this object and + // another object. + // + // Returns in modResults a vector of (function, instrumented) pairs where + // instrumented is true if stack modifications were successfully added. + void addModsAllFuncs(const std::set &mods, bool interproc, + std::vector> &modResults, + unsigned depthLimit = 0); + BPatchSnippetHandle* insertInitCallback(BPatch_snippet& callback); BPatchSnippetHandle* insertFiniCallback(BPatch_snippet& callback); @@ -154,8 +176,3 @@ class BPATCH_DLL_EXPORT BPatch_object { }; #endif - - - - - diff --git a/dyninstAPI/src/BPatch_object.C b/dyninstAPI/src/BPatch_object.C index fc22b3c780..4dc705bb0f 100644 --- a/dyninstAPI/src/BPatch_object.C +++ b/dyninstAPI/src/BPatch_object.C @@ -30,6 +30,9 @@ #include #include + +#include "stackanalysis.h" + #include "BPatch_object.h" #include "BPatch_image.h" #include "mapped_object.h" @@ -226,3 +229,430 @@ BPatchSnippetHandle* BPatch_object::insertFiniCallback(BPatch_snippet& callback) return NULL; } + +namespace { +void getCalledFuncs(BPatch_function *func, + std::set &callSet) { + const std::vector *callPoints = + func->findPoint(BPatch_subroutine); + if (callPoints == NULL) return; + for (auto callIter = callPoints->begin(); callIter != callPoints->end(); + callIter++) { + BPatch_point *callPoint = *callIter; + BPatch_function *f = callPoint->getCalledFunction(); + if (f != NULL) { + callSet.insert(f); + } + } +} + + +void resolveCalls(BPatch_function *func, + std::map &callResolutionMap) { + const std::vector *callPoints = + func->findPoint(BPatch_subroutine); + if (callPoints == NULL) return; + for (auto callIter = callPoints->begin(); callIter != callPoints->end(); + callIter++) { + BPatch_point *callPoint = *callIter; + Address callSite = (Address) callPoint->getAddress(); + BPatch_function *f = callPoint->getCalledFunction(); + if (f != NULL) { + Address calledAddr = (Address) f->getBaseAddr(); + callResolutionMap[callSite] = calledAddr; + } + } +} + + +void DLDFS(unsigned depthLimit, std::set allFuncsSet, + std::set &retSet) { + if (depthLimit == 0) { + retSet = allFuncsSet; + return; + } + + std::stack > workstack; + std::map donemap; + while (!allFuncsSet.empty()) { + BPatch_function *func = *allFuncsSet.begin(); + workstack.push(std::make_pair(func, depthLimit)); + while (!workstack.empty()) { + BPatch_function *currFunc = workstack.top().first; + unsigned currDepth = workstack.top().second; + workstack.pop(); + + // Add this function to the return set, and keep track of its depth + // in case we later discover a shorter path to this function + retSet.insert(currFunc); + donemap[currFunc] = currDepth; + allFuncsSet.erase(currFunc); + + // If we hit our depth limit, don't add children + if (currDepth == 0) continue; + + std::set calledSet; + getCalledFuncs(currFunc, calledSet); + for (auto iter = calledSet.begin(); iter != calledSet.end(); + iter++) { + BPatch_function *calledFunc = *iter; + if (allFuncsSet.find(calledFunc) != allFuncsSet.end()) { + // Child is not a library function, so add it with full + // depth limit + workstack.push(std::make_pair(calledFunc, depthLimit)); + } else if (donemap.find(calledFunc) != donemap.end()) { + // We've already visited this child. Only add it if we now + // have a shorter path to it. + if (donemap[calledFunc] < currDepth - 1) { + workstack.push(std::make_pair(calledFunc, + currDepth - 1)); + } + } else { + // Child is a library function, so decrease its depth limit + workstack.push(std::make_pair(calledFunc, currDepth - 1)); + } + } + } + } +} + + +class topoCycleVisitor { +public: + topoCycleVisitor() : currCycle(0) {} + + void topoCycleVisit(BPatch_function *func, + std::set &unvisitedSet, + std::queue, bool> > + &sortedSetList) { + // Detect cycles in call graph + if (currCallSet.find(func) != currCallSet.end()) { + markCycle(func); + return; + } + + currCallStack.push(func); + currCallSet.insert(func); + + // Recurse until all descendants have been visited + std::set calledFuncs; + getCalledFuncs(func, calledFuncs); + for (auto iter = calledFuncs.begin(); iter != calledFuncs.end(); + iter++) { + BPatch_function *childFunc = *iter; + if (unvisitedSet.find(childFunc) != unvisitedSet.end()) { + topoCycleVisit(childFunc, unvisitedSet, sortedSetList); + } else if (cycleGroupMap.find(childFunc) != cycleGroupMap.end()) { + // childFunc is part of a cycle. Detect if we need to add + // functions along our current call path to that cycle. + BPatch_function *otherFuncInCycle = getFirstNodeByGroup( + currCallStack, cycleGroupMap[childFunc]); + if (otherFuncInCycle != NULL) { + markCycle(otherFuncInCycle); + } + } + } + + // Mark this node as visited + unvisitedSet.erase(func); + assert(currCallStack.top() == func); + currCallStack.pop(); + currCallSet.erase(func); + + if (cycleGroupMap.find(func) != cycleGroupMap.end()) { + // This node is part of a cycle + if (!currCallStack.empty() && + cycleGroupMap.find(currCallStack.top()) != + cycleGroupMap.end() && + cycleGroupMap[currCallStack.top()] == cycleGroupMap[func]) { + // The parent node is also part of this cycle. We'll deal with + // this cycle when we finish visiting the parent. + return; + } else { + // This is the last node to be visited in this cycle. Let's add + // the merged cycle to the sorted list. + const std::set &mergedCycle = + cycleSetMap[cycleGroupMap[func]]; + sortedSetList.push(std::make_pair(mergedCycle, true)); + } + } else { + // This node is not part of a cycle. Add the node to the sorted + // list. + std::set funcSet; + funcSet.insert(func); + sortedSetList.push(std::make_pair(funcSet, false)); + } + } + +private: + std::stack currCallStack; + std::set currCallSet; + std::map cycleGroupMap; + std::map > cycleSetMap; + unsigned currCycle; + + // Marks all nodes on the call stack up to func as part of the same cycle. + // If any of those nodes are part of different cycles, those cycles are + // merged into the new cycle. + void markCycle(BPatch_function *func) { + std::set mergeSet; + std::stack currCallStackCopy = currCallStack; + + // Update mappings for the passed-in func + if (cycleGroupMap.find(func) != cycleGroupMap.end()) { + mergeSet.insert(cycleGroupMap[func]); + } + cycleGroupMap[func] = currCycle; + cycleSetMap[currCycle].insert(func); + + // Update our mappings with all other nodes in the cycle. Keep track of + // other cycles that we intersect. + while (currCallStackCopy.top() != func) { + BPatch_function *currFunc = currCallStackCopy.top(); + if (cycleGroupMap.find(currFunc) != cycleGroupMap.end()) { + mergeSet.insert(cycleGroupMap[currFunc]); + } + cycleGroupMap[currFunc] = currCycle; + cycleSetMap[currCycle].insert(currFunc); + currCallStackCopy.pop(); + } + + // Update mappings for all intersecting cycles (merge those cycles into + // this one). + for (auto iter = mergeSet.begin(); iter != mergeSet.end(); iter++) { + unsigned cycleNum = *iter; + for (auto iter2 = cycleSetMap[cycleNum].begin(); + iter2 != cycleSetMap[cycleNum].end(); iter2++) { + BPatch_function *f = *iter2; + cycleGroupMap[f] = currCycle; + cycleSetMap[currCycle].insert(f); + } + cycleSetMap.erase(cycleNum); + } + + currCycle++; + } + + // Returns the first node placed on callStack that is part of the cycle + // specified by cycleNum. Returns NULL if no matching node is found. + BPatch_function *getFirstNodeByGroup( + std::stack callStack, unsigned cycleNum) { + BPatch_function *firstNode = NULL; + while (!callStack.empty()) { + BPatch_function *currNode = callStack.top(); + callStack.pop(); + if (cycleGroupMap.find(currNode) != cycleGroupMap.end() && + cycleGroupMap[currNode] == cycleNum) { + firstNode = currNode; + } + } + return firstNode; + } +}; + + +void topoCycleSort(std::set unvisitedSet, + std::queue, bool> > &sortedSetList) { + topoCycleVisitor tcv; + while (!unvisitedSet.empty()) { + BPatch_function *func = *unvisitedSet.begin(); + tcv.topoCycleVisit(func, unvisitedSet, sortedSetList); + } +} + + +void funcSummaryFixpoint(std::set funcSet, + const std::map &callResolutionMap, + std::map &functionSummaries) { + // Determine which functions in the set can be summarized + std::set
summarizableSet; + for (auto iter = funcSet.begin(); iter != funcSet.end(); iter++) { + BPatch_function *func = *iter; + StackAnalysis sa(func->lowlevel_func()->ifunc()); + if (sa.canGetFunctionSummary()) { + Address funcBaseAddr = (Address) func->getBaseAddr(); + summarizableSet.insert(funcBaseAddr); + } + } + + // Determine which functions in the set call each other + std::map > calleeToCallerMap; + for (auto callerIter = funcSet.begin(); callerIter != funcSet.end(); + callerIter++) { + BPatch_function *caller = *callerIter; + std::set calleeSet; + getCalledFuncs(caller, calleeSet); + for (auto calleeIter = calleeSet.begin(); calleeIter != calleeSet.end(); + calleeIter++) { + BPatch_function *callee = *calleeIter; + if (funcSet.find(callee) != funcSet.end()) { + calleeToCallerMap[callee].insert(caller); + } + } + } + + // Iteratively generate function summaries until a fixed point is reached + std::queue worklist; + std::set workset; + for (auto iter = funcSet.begin(); iter != funcSet.end(); iter++) { + BPatch_function *f = *iter; + worklist.push(f); + workset.insert(f); + } + while (!worklist.empty()) { + BPatch_function *currFunc = worklist.front(); + worklist.pop(); + workset.erase(currFunc); + + // Delete any cached work and regenerate function summary + currFunc->lowlevel_func()->freeStackMod(); + StackAnalysis sa(currFunc->lowlevel_func()->ifunc(), callResolutionMap, + functionSummaries, summarizableSet); + Address funcBaseAddr = (Address) currFunc->getBaseAddr(); + StackAnalysis::TransferSet summary; + bool summarySuccess = sa.getFunctionSummary(summary); + + // If summary has changed, add affected functions back to worklist + if (summary != functionSummaries[funcBaseAddr]) { + functionSummaries[funcBaseAddr] = summary; + for (auto callerIter = calleeToCallerMap[currFunc].begin(); + callerIter != calleeToCallerMap[currFunc].end(); callerIter++) { + BPatch_function *caller = *callerIter; + // Only add to worklist if caller isn't already in the list + if (workset.find(caller) == workset.end()) { + worklist.push(caller); + workset.insert(caller); + } + } + } + + // If the summary failed, delete any default summary created + if (!summarySuccess) { + functionSummaries.erase(funcBaseAddr); + } + } +} + + +void addModsFuncSet(const std::set &mods, + const std::set &addModFuncs, + std::pair, bool> &funcSetPair, + std::map &functionSummaries, + std::map &callResolutionMap, + std::vector > &modResults) { + std::set funcSet = funcSetPair.first; + bool isCycle = funcSetPair.second; + + if (isCycle) { + // Iteratively generate function summaries for the cycle + funcSummaryFixpoint(funcSet, callResolutionMap, functionSummaries); + + // Instrument the necessary functions in the cycle + for (auto iter = funcSet.begin(); iter != funcSet.end(); iter++) { + BPatch_function *func = *iter; + if (addModFuncs.find(func) != addModFuncs.end()) { + bool success = func->addMods(mods); + modResults.push_back(std::make_pair(func, success)); + } + func->lowlevel_func()->freeStackMod(); + } + } else { + // Generate a function summary and save for future analysis + assert(funcSet.size() == 1); + BPatch_function *func = *funcSet.begin(); + StackAnalysis sa(func->lowlevel_func()->ifunc(), callResolutionMap, + functionSummaries); + Address funcBaseAddr = (Address) func->getBaseAddr(); + StackAnalysis::TransferSet summary; + if (sa.getFunctionSummary(summary)) { + functionSummaries[funcBaseAddr] = summary; + } + + if (addModFuncs.find(func) != addModFuncs.end()) { + // This function also needs to be instrumented + bool success = func->addMods(mods); + modResults.push_back(std::make_pair(func, success)); + } + func->lowlevel_func()->freeStackMod(); + } +} + +} // namespace + +void BPatch_object::addModsAllFuncs(const std::set &mods, + bool interproc, + std::vector > &modResults, + unsigned depthLimit) { + // Get list of functions in this object + std::set allModFuncs; + std::vector objModules; + modules(objModules); + for (auto iter = objModules.begin(); iter != objModules.end(); iter++) { + BPatch_module *module = *iter; + vector *funcs = module->getProcedures(true); + for (auto funcIter = funcs->begin(); funcIter != funcs->end(); + funcIter++) { + BPatch_function *func = *funcIter; + if (!func->isInstrumentable()) { + stackmods_printf("Function %s is uninstrumentable\n", + func->getName().c_str()); + continue; + } + allModFuncs.insert(func); + } + } + + if (interproc) { + // Do a depth-limited DFS to get functions we need to consider from + // other objects. + std::set allFuncs; + DLDFS(depthLimit, allModFuncs, allFuncs); + stackmods_printf("FUNCTIONS TO ANALYZE:\n"); + for (auto iter = allFuncs.begin(); iter != allFuncs.end(); iter++) { + BPatch_function *f = *iter; + stackmods_printf("%s\n", f->getName().c_str()); + } + + // Map function calls to PLT-resolved addresses (for use by + // StackAnalysis). + std::map callResolutionMap; + for (auto iter = allFuncs.begin(); iter != allFuncs.end(); iter++) { + BPatch_function *f = *iter; + resolveCalls(f, callResolutionMap); + } + + // Determine order of function analysis via topological sort of call + // graph. + std::queue, bool> > sortedSetList; + topoCycleSort(allFuncs, sortedSetList); + + std::queue, bool> > ssl2 = + sortedSetList; + stackmods_printf("Topological ordering:\n"); + while (!ssl2.empty()) { + std::set fSet = ssl2.front().first; + bool cycle = ssl2.front().second; + ssl2.pop(); + stackmods_printf("{"); + for (auto iter = fSet.begin(); iter != fSet.end(); iter++) { + stackmods_printf("%s (%lx), ", (*iter)->getName().c_str(), + (*iter)->getBaseAddr()); + } + stackmods_printf("}, %s\n", cycle ? "TRUE" : "FALSE"); + } + + // Analyze functions in topological order + std::map funcEntryToSummary; + while (!sortedSetList.empty()) { + addModsFuncSet(mods, allModFuncs, sortedSetList.front(), + funcEntryToSummary, callResolutionMap, modResults); + sortedSetList.pop(); + } + } else { + for (auto iter = allModFuncs.begin(); iter != allModFuncs.end(); + iter++) { + BPatch_function *func = *iter; + modResults.push_back(std::make_pair(func, func->addMods(mods))); + } + } +} diff --git a/dyninstAPI/src/function.C b/dyninstAPI/src/function.C index c2166877e7..88142f3dee 100644 --- a/dyninstAPI/src/function.C +++ b/dyninstAPI/src/function.C @@ -1646,6 +1646,8 @@ AnnotationClass Stack_Anno_Block_Effects(std::string("Stack_Anno_Block_Effects")); AnnotationClass Stack_Anno_Insn_Effects(std::string("Stack_Anno_Insn_Effects")); +AnnotationClass + Stack_Anno_Call_Effects(std::string("Stack_Anno_Call_Effects")); void func_instance::freeStackMod() { // Free stack analysis intervals StackAnalysis::Intervals *i = NULL; @@ -1664,5 +1666,11 @@ void func_instance::freeStackMod() { ifunc()->getAnnotation(ie, Stack_Anno_Insn_Effects); ifunc()->removeAnnotation(Stack_Anno_Insn_Effects); if (ie != NULL) delete ie; + + // Free stack analysis call effects + StackAnalysis::CallEffects *ce = NULL; + ifunc()->getAnnotation(ce, Stack_Anno_Call_Effects); + ifunc()->removeAnnotation(Stack_Anno_Call_Effects); + if (ce != NULL) delete ce; } #endif From f25e8f715710c761b926261ff93a0ad9b4b91015 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Wed, 17 Aug 2016 14:07:33 -0500 Subject: [PATCH 026/180] Allow BPatch_function::findPoint on uninstrumentable functions. findPoint is useful for interprocedural analysis in StackMod, even if the function passed in is uninstrumentable. --- dyninstAPI/src/BPatch_function.C | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dyninstAPI/src/BPatch_function.C b/dyninstAPI/src/BPatch_function.C index 1d3fe87131..80233c4722 100644 --- a/dyninstAPI/src/BPatch_function.C +++ b/dyninstAPI/src/BPatch_function.C @@ -602,10 +602,6 @@ BPatch_Vector *BPatch_function::findPoint( if (!mod->isValid()) return NULL; - // if the function is not instrumentable, we won't find the point - if (!isInstrumentable()) - return NULL; - BPatch_Vector *result = new BPatch_Vector; switch(loc) { From dfa440eb1bb9220d6c323fa34bc8f61c25928224 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 17 Aug 2016 17:20:54 -0700 Subject: [PATCH 027/180] symtabAPI: use the known type for new relocations In emitElf::createRelocationSections(), new relocations were calling getGlobalRelType to determine their type. However, this didn't take the symbol type into account, so functions on PPC64 were getting GLOB_DAT instead of JMP_SLOT, and they didn't work at all when called. Each new relocationEntry already knows its type, so use getRelType(). --- symtabAPI/src/emitElf.C | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/symtabAPI/src/emitElf.C b/symtabAPI/src/emitElf.C index 12dae8e329..f7edb211fb 100644 --- a/symtabAPI/src/emitElf.C +++ b/symtabAPI/src/emitElf.C @@ -2121,10 +2121,10 @@ void emitElf::createRelocationSections(std::vector &r rels[j].r_offset = newRels[i].rel_addr() + library_adjust; if (dynSymNameMapping.find(newRels[i].name()) != dynSymNameMapping.end()) { rels[j].r_info = ElfTypes::makeRelocInfo(dynSymNameMapping[newRels[i].name()], - relocationEntry::getGlobalRelType(obj->getAddressWidth())); + newRels[i].getRelType()); } else { rels[j].r_info = ElfTypes::makeRelocInfo((unsigned long) (STN_UNDEF), - relocationEntry::getGlobalRelType(obj->getAddressWidth())); + newRels[i].getRelType()); } j++; l++; @@ -2134,10 +2134,10 @@ void emitElf::createRelocationSections(std::vector &r //if( relas[k].r_addend ) relas[k].r_addend += library_adjust; if (dynSymNameMapping.find(newRels[i].name()) != dynSymNameMapping.end()) { relas[k].r_info = ElfTypes::makeRelocInfo(dynSymNameMapping[newRels[i].name()], - relocationEntry::getGlobalRelType(obj->getAddressWidth())); + newRels[i].getRelType()); } else { relas[k].r_info = ElfTypes::makeRelocInfo((unsigned long) (STN_UNDEF), - relocationEntry::getGlobalRelType(obj->getAddressWidth())); + newRels[i].getRelType()); } k++; m++; From 21dcf8d8724f8d6f04e4ece9bf27e21f7dcb1b3a Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Wed, 4 May 2016 23:42:42 -0400 Subject: [PATCH 028/180] regenerate dynC lexer/parser --- dynC_API/src/C.l | 2 + dynC_API/src/C.y | 5 + dynC_API/src/dynC.tab.C | 1800 ++++++++++++++++++--------------------- dynC_API/src/dynC.tab.h | 228 +++-- dynC_API/src/lex.dynC.C | 460 +++++----- 5 files changed, 1167 insertions(+), 1328 deletions(-) diff --git a/dynC_API/src/C.l b/dynC_API/src/C.l index 5dfe4f8c23..f9616b432f 100644 --- a/dynC_API/src/C.l +++ b/dynC_API/src/C.l @@ -3,6 +3,8 @@ %x comment %x stringmode %option yylineno +%option outfile="lex.dynC.C" +%option prefix="dynC" D[0-9] L[a-zA-Z_] diff --git a/dynC_API/src/C.y b/dynC_API/src/C.y index cc96c0b7ef..b3cede62ae 100644 --- a/dynC_API/src/C.y +++ b/dynC_API/src/C.y @@ -1,3 +1,7 @@ +%output "dynC.tab.C" +%defines "dynC.tab.h" +%name-prefix "dynC" + %{ /* * Yacc will define token IF, conflicting with dyn_regs.h @@ -8,6 +12,7 @@ #undef RETURN + #include #include #include diff --git a/dynC_API/src/dynC.tab.C b/dynC_API/src/dynC.tab.C index 9bde446c37..e81d5cb73a 100644 --- a/dynC_API/src/dynC.tab.C +++ b/dynC_API/src/dynC.tab.C @@ -1,19 +1,19 @@ -/* A Bison parser, made by GNU Bison 2.7. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. - + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program 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 General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -26,7 +26,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.7" +#define YYBISON_VERSION "3.0.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -63,15 +63,15 @@ #define yyparse dynCparse #define yylex dynClex #define yyerror dynCerror -#define yylval dynClval -#define yychar dynCchar #define yydebug dynCdebug #define yynerrs dynCnerrs + +#define yylval dynClval +#define yychar dynCchar #define yylloc dynClloc /* Copy the first part of user declarations. */ -/* Line 371 of yacc.c */ -#line 1 "../src/C.y" +#line 5 "C.y" /* yacc.c:339 */ /* * Yacc will define token IF, conflicting with dyn_regs.h @@ -82,6 +82,7 @@ #undef RETURN + #include #include #include @@ -135,14 +136,13 @@ extern int line_num; std::vector endSnippets; -/* Line 371 of yacc.c */ -#line 140 "dynC.tab.c" +#line 140 "dynC.tab.C" /* yacc.c:339 */ -# ifndef YY_NULL +# ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULL nullptr +# define YY_NULLPTR nullptr # else -# define YY_NULL 0 +# define YY_NULLPTR 0 # endif # endif @@ -158,7 +158,7 @@ std::vector endSnippets; by #include "dynC.tab.h". */ #ifndef YY_DYNC_DYNC_TAB_H_INCLUDED # define YY_DYNC_DYNC_TAB_H_INCLUDED -/* Enabling traces. */ +/* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif @@ -166,105 +166,104 @@ std::vector endSnippets; extern int dynCdebug; #endif -/* Tokens. */ +/* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - KNOWN_ERROR_TOK = 258, - IDENTIFIER = 259, - CONSTANT = 260, - STRING = 261, - TYPE = 262, - NUMBER = 263, - ERROR = 264, - EOL = 265, - SIZEOF = 266, - D_TRUE = 267, - D_FALSE = 268, - PTR_OP = 269, - INC_OP = 270, - DEC_OP = 271, - LEFT_OP = 272, - RIGHT_OP = 273, - LEFT_ASSIGN = 274, - RIGHT_ASSIGN = 275, - AND_ASSIGN = 276, - XOR_ASSIGN = 277, - OR_ASSIGN = 278, - TYPE_NAME = 279, - TYPEDEF = 280, - EXTERN = 281, - STATIC = 282, - CHAR = 283, - SHORT = 284, - INT = 285, - LONG = 286, - SIGNED = 287, - UNSIGNED = 288, - FLOAT = 289, - DOUBLE = 290, - CONST = 291, - VOID = 292, - STRUCT = 293, - UNION = 294, - ENUM = 295, - ELLIPSIS = 296, - IF = 297, - LOCAL = 298, - PARAM = 299, - GLOBAL = 300, - FUNC = 301, - DYNINST = 302, - INST = 303, - REGISTER = 304, - NEWLINE = 305, - CASE = 306, - DEFAULT = 307, - SWITCH = 308, - RETURN = 309, - NILL = 310, - EOF_TOK = 311, - COMMA = 312, - AMPERSAND = 313, - ASTERISK = 314, - DOT = 315, - NOT = 316, - OR = 317, - AND = 318, - NOT_EQ = 319, - EQ = 320, - GREATER_EQ = 321, - LESS_EQ = 322, - COLON = 323, - SEMI = 324, - END_BLOCK = 325, - START_BLOCK = 326, - DOLLAR = 327, - BACKTICK = 328, - ASSIGN = 329, - SUB_ASSIGN = 330, - ADD_ASSIGN = 331, - MOD_ASSIGN = 332, - DIV_ASSIGN = 333, - MUL_ASSIGN = 334, - OR_OP = 335, - AND_OP = 336, - NCLOSE = 337, - NOPEN = 338, - LOWER_THAN_ELSE = 339, - ELSE = 340, - LOWER_THAN_DEREF = 341 - }; + enum yytokentype + { + KNOWN_ERROR_TOK = 258, + IDENTIFIER = 259, + CONSTANT = 260, + STRING = 261, + TYPE = 262, + NUMBER = 263, + ERROR = 264, + EOL = 265, + SIZEOF = 266, + D_TRUE = 267, + D_FALSE = 268, + PTR_OP = 269, + INC_OP = 270, + DEC_OP = 271, + LEFT_OP = 272, + RIGHT_OP = 273, + LEFT_ASSIGN = 274, + RIGHT_ASSIGN = 275, + AND_ASSIGN = 276, + XOR_ASSIGN = 277, + OR_ASSIGN = 278, + TYPE_NAME = 279, + TYPEDEF = 280, + EXTERN = 281, + STATIC = 282, + CHAR = 283, + SHORT = 284, + INT = 285, + LONG = 286, + SIGNED = 287, + UNSIGNED = 288, + FLOAT = 289, + DOUBLE = 290, + CONST = 291, + VOID = 292, + STRUCT = 293, + UNION = 294, + ENUM = 295, + ELLIPSIS = 296, + IF = 297, + LOCAL = 298, + PARAM = 299, + GLOBAL = 300, + FUNC = 301, + DYNINST = 302, + INST = 303, + REGISTER = 304, + NEWLINE = 305, + CASE = 306, + DEFAULT = 307, + SWITCH = 308, + RETURN = 309, + NILL = 310, + EOF_TOK = 311, + DOT = 312, + ASTERISK = 313, + AMPERSAND = 314, + COMMA = 315, + NOT = 316, + OR = 317, + AND = 318, + LESS_EQ = 319, + GREATER_EQ = 320, + EQ = 321, + NOT_EQ = 322, + COLON = 323, + SEMI = 324, + START_BLOCK = 325, + END_BLOCK = 326, + DOLLAR = 327, + BACKTICK = 328, + AND_OP = 329, + OR_OP = 330, + MUL_ASSIGN = 331, + DIV_ASSIGN = 332, + MOD_ASSIGN = 333, + ADD_ASSIGN = 334, + SUB_ASSIGN = 335, + ASSIGN = 336, + NOPEN = 337, + NCLOSE = 338, + LOWER_THAN_ELSE = 339, + ELSE = 340, + LOWER_THAN_DEREF = 341 + }; #endif - +/* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE + +union YYSTYPE { -/* Line 387 of yacc.c */ -#line 66 "../src/C.y" +#line 71 "C.y" /* yacc.c:355 */ int ival; long lval; @@ -294,50 +293,38 @@ typedef union YYSTYPE std::vector > *snippetStringListPair; std::pair *snippetStringPair; +#line 297 "dynC.tab.C" /* yacc.c:355 */ +}; -/* Line 387 of yacc.c */ -#line 300 "dynC.tab.c" -} YYSTYPE; +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif +/* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; -} YYLTYPE; -# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +}; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif + extern YYSTYPE dynClval; extern YYLTYPE dynClloc; -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int dynCparse (void *YYPARSE_PARAM); -#else -int dynCparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus int dynCparse (void); -#else -int dynCparse (); -#endif -#endif /* ! YYPARSE_PARAM */ #endif /* !YY_DYNC_DYNC_TAB_H_INCLUDED */ /* Copy the second part of user declarations. */ -/* Line 390 of yacc.c */ -#line 341 "dynC.tab.c" +#line 328 "dynC.tab.C" /* yacc.c:358 */ #ifdef short # undef short @@ -351,11 +338,8 @@ typedef unsigned char yytype_uint8; #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; #else -typedef short int yytype_int8; +typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 @@ -375,8 +359,7 @@ typedef short int yytype_int16; # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else @@ -398,6 +381,33 @@ typedef short int yytype_int16; # endif #endif +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) @@ -405,24 +415,26 @@ typedef short int yytype_int16; # define YYUSE(E) /* empty */ #endif -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(N) (N) +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") #else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int yyi) -#else -static int -YYID (yyi) - int yyi; +# define YY_INITIAL_VALUE(Value) Value #endif -{ - return yyi; -} +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif + #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ @@ -440,8 +452,7 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS @@ -453,8 +464,8 @@ YYID (yyi) # endif # ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely @@ -470,7 +481,7 @@ YYID (yyi) # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) + && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 @@ -478,15 +489,13 @@ YYID (yyi) # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif @@ -496,8 +505,8 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ - || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ - && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc @@ -523,16 +532,16 @@ union yyalloc elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) #endif @@ -551,7 +560,7 @@ union yyalloc for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ - while (YYID (0)) + while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ @@ -559,7 +568,7 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 45 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 516 +#define YYLAST 498 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 104 @@ -567,17 +576,19 @@ union yyalloc #define YYNNTS 17 /* YYNRULES -- Number of rules. */ #define YYNRULES 75 -/* YYNRULES -- Number of states. */ +/* YYNSTATES -- Number of states. */ #define YYNSTATES 147 -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 341 -#define YYTRANSLATE(YYX) \ +#define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -618,63 +629,17 @@ static const yytype_uint8 yytranslate[] = }; #if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 5, 8, 13, 19, 28, 38, 40, - 43, 45, 48, 52, 57, 59, 61, 64, 67, 73, - 81, 83, 87, 94, 101, 102, 104, 108, 110, 112, - 114, 118, 122, 126, 130, 134, 138, 142, 146, 148, - 150, 152, 154, 158, 162, 166, 171, 174, 177, 179, - 181, 183, 187, 189, 191, 193, 197, 201, 205, 207, - 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, - 251, 255, 257, 260, 263, 266 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = -{ - 105, 0, -1, 108, -1, 107, 4, -1, 107, 4, - 85, 119, -1, 107, 4, 80, 8, 81, -1, 107, - 4, 80, 81, 85, 98, 118, 99, -1, 107, 4, - 80, 8, 81, 85, 98, 118, 99, -1, 7, -1, - 27, 107, -1, 109, -1, 108, 109, -1, 94, 108, - 93, -1, 108, 94, 108, 93, -1, 1, -1, 9, - -1, 106, 75, -1, 119, 75, -1, 42, 100, 114, - 101, 110, -1, 42, 100, 114, 101, 110, 96, 110, - -1, 109, -1, 98, 108, 99, -1, 47, 79, 4, - 100, 112, 101, -1, 46, 79, 4, 100, 112, 101, - -1, -1, 119, -1, 112, 57, 119, -1, 12, -1, - 13, -1, 113, -1, 119, 102, 119, -1, 119, 103, - 119, -1, 119, 65, 119, -1, 119, 67, 119, -1, - 119, 66, 119, -1, 119, 64, 119, -1, 114, 63, - 114, -1, 114, 62, 114, -1, 45, -1, 43, -1, - 44, -1, 4, -1, 46, 79, 4, -1, 115, 79, - 4, -1, 115, 79, 8, -1, 116, 80, 119, 81, - -1, 70, 116, -1, 84, 116, -1, 8, -1, 6, - -1, 117, -1, 118, 57, 117, -1, 116, -1, 117, - -1, 55, -1, 49, 79, 4, -1, 47, 79, 4, - -1, 119, 70, 119, -1, 111, -1, 116, 85, 119, - -1, 116, 87, 119, -1, 116, 86, 119, -1, 116, - 90, 119, -1, 116, 89, 119, -1, 116, 88, 119, - -1, 119, 71, 119, -1, 119, 72, 119, -1, 119, - 68, 119, -1, 119, 69, 119, -1, 119, 73, 119, - -1, 100, 119, 101, -1, 120, -1, 116, 15, -1, - 15, 116, -1, 116, 16, -1, 16, 116, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 164, 164, 187, 207, 225, 256, 289, 337, 342, - 355, 361, 366, 374, 384, 389, 395, 400, 411, 419, - 430, 432, 439, 454, 469, 474, 480, 489, 493, 500, - 501, 506, 511, 516, 521, 526, 531, 536, 544, 550, - 556, 565, 574, 584, 610, 630, 641, 645, 652, 658, - 667, 673, 679, 680, 681, 682, 691, 759, 765, 770, - 776, 782, 788, 794, 800, 806, 812, 818, 824, 830, - 839, 840, 849, 855, 861, 867 + 0, 169, 169, 192, 212, 230, 261, 294, 342, 347, + 360, 366, 371, 379, 389, 394, 400, 405, 416, 424, + 435, 437, 444, 459, 474, 479, 485, 494, 498, 505, + 506, 511, 516, 521, 526, 531, 536, 541, 549, 555, + 561, 570, 579, 589, 615, 635, 646, 650, 657, 663, + 672, 678, 684, 685, 686, 687, 696, 764, 770, 775, + 781, 787, 793, 799, 805, 811, 817, 823, 829, 835, + 844, 845, 854, 860, 866, 872 }; #endif @@ -691,23 +656,24 @@ static const char *const yytname[] = "LONG", "SIGNED", "UNSIGNED", "FLOAT", "DOUBLE", "CONST", "VOID", "STRUCT", "UNION", "ENUM", "ELLIPSIS", "IF", "LOCAL", "PARAM", "GLOBAL", "FUNC", "DYNINST", "INST", "REGISTER", "NEWLINE", "CASE", "DEFAULT", - "SWITCH", "RETURN", "NILL", "EOF_TOK", "COMMA", "AMPERSAND", "ASTERISK", - "DOT", "NOT", "OR", "AND", "NOT_EQ", "EQ", "GREATER_EQ", "LESS_EQ", - "'+'", "'-'", "'*'", "'/'", "'%'", "'|'", "COLON", "SEMI", "END_BLOCK", - "START_BLOCK", "DOLLAR", "BACKTICK", "'['", "']'", "'!'", "'~'", "'&'", - "ASSIGN", "SUB_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", "DIV_ASSIGN", - "MUL_ASSIGN", "OR_OP", "AND_OP", "NCLOSE", "NOPEN", "LOWER_THAN_ELSE", - "ELSE", "LOWER_THAN_DEREF", "'{'", "'}'", "'('", "')'", "'<'", "'>'", - "$accept", "start", "var_declaration", "var_decl_modifiers", - "statement_list", "statement", "block", "func_call", "param_list", - "bool_constant", "bool_expression", "var_modifiers", "variable_expr", - "constant", "const_list", "arith_expression", "inc_decr_expr", YY_NULL + "SWITCH", "RETURN", "NILL", "EOF_TOK", "DOT", "ASTERISK", "AMPERSAND", + "COMMA", "NOT", "OR", "AND", "LESS_EQ", "GREATER_EQ", "EQ", "NOT_EQ", + "'+'", "'-'", "'*'", "'/'", "'%'", "'|'", "COLON", "SEMI", "START_BLOCK", + "END_BLOCK", "DOLLAR", "BACKTICK", "'['", "']'", "'!'", "'~'", "'&'", + "AND_OP", "OR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "MOD_ASSIGN", + "ADD_ASSIGN", "SUB_ASSIGN", "ASSIGN", "NOPEN", "NCLOSE", + "LOWER_THAN_ELSE", "ELSE", "LOWER_THAN_DEREF", "'{'", "'}'", "'('", + "')'", "'<'", "'>'", "$accept", "start", "var_declaration", + "var_decl_modifiers", "statement_list", "statement", "block", + "func_call", "param_list", "bool_constant", "bool_expression", + "var_modifiers", "variable_expr", "constant", "const_list", + "arith_expression", "inc_decr_expr", YY_NULLPTR }; #endif # ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, @@ -724,35 +690,40 @@ static const yytype_uint16 yytoknum[] = }; # endif -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 104, 105, 106, 106, 106, 106, 106, 107, 107, - 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, - 110, 110, 111, 111, 112, 112, 112, 113, 113, 114, - 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, - 115, 116, 116, 116, 116, 116, 116, 116, 117, 117, - 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 120, 120, 120, 120 -}; +#define YYPACT_NINF -91 -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-91))) + +#define YYTABLE_NINF -3 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = { - 0, 2, 1, 2, 4, 5, 8, 9, 1, 2, - 1, 2, 3, 4, 1, 1, 2, 2, 5, 7, - 1, 3, 6, 6, 0, 1, 3, 1, 1, 1, - 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, - 1, 1, 3, 3, 3, 4, 2, 2, 1, 1, - 1, 3, 1, 1, 1, 3, 3, 3, 1, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 1, 2, 2, 2, 2 + 287, -91, -91, -91, -91, -91, -91, 23, 23, -4, + -90, -91, -91, -91, -57, -48, -9, -91, 23, 23, + 287, 398, 26, -20, 67, 45, -91, -91, -6, 337, + -91, 71, -91, -5, 15, 15, -91, 352, 92, 94, + 95, 15, -91, 110, 62, -91, -91, -71, 287, -91, + 0, -91, -91, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, -91, 97, -91, -91, + -91, -51, 390, 2, 3, -91, -91, -91, -3, 398, + 169, -91, -91, 118, -91, -91, -91, -91, -91, -91, + -8, -8, 36, 36, 36, -91, -91, 352, 352, 339, + 398, 398, 398, 398, 398, 398, 398, 398, 32, 28, + 177, -91, -91, 58, -91, 287, -91, 27, 177, 177, + 177, 177, 177, 177, -54, 177, -53, 30, 29, 228, + 339, 398, -91, -91, 38, 9, -91, -91, 177, 9, + -91, -42, -40, 9, -91, -91, -91 }; -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 14, 41, 49, 8, 48, 15, 0, 0, 0, @@ -763,218 +734,197 @@ static const yytype_uint8 yydefact[] = 0, 72, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 27, 28, 29, 0, 0, 42, 56, 55, 12, 70, 0, 0, - 0, 43, 44, 0, 59, 61, 60, 64, 63, 62, + 0, 43, 44, 0, 62, 63, 64, 60, 61, 59, 67, 68, 57, 65, 66, 69, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, - 4, 13, 45, 37, 36, 0, 20, 18, 35, 32, - 34, 33, 30, 31, 0, 25, 0, 5, 0, 0, + 4, 13, 45, 37, 36, 0, 20, 18, 33, 34, + 32, 35, 30, 31, 0, 25, 0, 5, 0, 0, 0, 0, 23, 22, 0, 0, 21, 19, 26, 0, 50, 0, 0, 0, 6, 7, 51 }; -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 22, 23, 24, 25, 26, 117, 27, 124, 70, - 71, 28, 29, 30, 141, 31, 32 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -126 -static const yytype_int16 yypact[] = + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = { - 287, -126, -126, -126, -126, -126, -126, 23, 23, -1, - -85, -126, -126, -126, -62, -51, -48, -126, 23, 23, - 287, 416, 25, -4, 53, 45, -126, -126, -6, 112, - -126, 118, -126, 19, 21, 21, -126, 364, 95, 98, - 99, 21, -126, 110, 62, -126, -126, -56, 287, -126, - 66, -126, -126, 416, 416, 416, 416, 416, 416, 416, - 416, 416, 416, 416, 416, 416, -126, 100, -126, -126, - -126, -42, 385, 8, 9, -126, -126, -126, -3, 416, - 169, -126, -126, 177, -126, -126, -126, -126, -126, -126, - -8, -8, 39, 39, 39, -126, -126, 364, 364, 346, - 416, 416, 416, 416, 416, 416, 416, 416, 32, 35, - 78, -126, -126, 58, -126, 287, -126, 26, 78, 78, - 78, 78, 78, 78, -54, 78, -53, 38, 40, 228, - 346, 416, -126, -126, 42, 1, -126, -126, 78, 1, - -126, -49, -44, 1, -126, -126, -126 + -91, -91, -91, 115, -18, -24, -2, -91, 40, -91, + -69, -91, 6, -31, 10, -21, -91 }; -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int8 yypgoto[] = + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = { - -126, -126, -126, 115, -18, -24, 6, -126, 34, -126, - -2, -126, 4, -125, 3, -21, -126 + -1, 22, 23, 24, 25, 26, 117, 27, 124, 70, + 71, 28, 29, 30, 141, 31, 32 }; -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -3 + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 44, 49, 43, 131, 131, 108, 4, 3, 143, 5, - 140, 34, 35, 143, 140, 37, 72, 38, 146, 49, - 97, 98, 41, 42, 78, 45, 9, 2, 39, 79, - 80, 40, 83, 84, 85, 86, 87, 88, 89, 90, + 44, 49, 43, 4, 81, 108, 131, 131, 82, 78, + 37, 97, 98, 34, 35, 3, 72, 5, 143, 49, + 143, 79, 38, 9, 41, 42, 45, 2, 113, 114, + 80, 39, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, -2, 1, 132, 133, 2, - 144, 3, 4, 5, 6, 145, 49, 47, 110, 99, + 99, 3, 4, 5, 6, 46, 49, 144, 110, 145, 7, 8, 62, 63, 64, 65, 11, 12, 13, 33, - 81, 46, 9, 50, 82, 116, 72, 72, 109, 118, + 40, 47, 9, 50, 67, 116, 72, 72, 109, 118, 119, 120, 121, 122, 123, 125, 125, 10, 11, 12, - 13, 14, 15, 18, 16, 113, 114, 129, 67, 73, - 17, 53, 74, 75, 96, 49, 116, 19, 106, 107, - 138, 1, 65, 127, 2, 18, 3, 4, 5, 6, - 128, 98, 130, 134, 36, 7, 8, 51, 52, 19, - 60, 61, 62, 63, 64, 65, 137, 9, 135, 48, - 139, 126, 142, 0, 0, 21, 60, 61, 62, 63, - 64, 65, 10, 11, 12, 13, 14, 15, 0, 16, + 13, 14, 15, 18, 16, 53, 73, 129, 74, 75, + 17, 96, 106, 107, 140, 49, 116, 19, 140, 65, + 138, 1, 146, 127, 2, 18, 3, 4, 5, 6, + 128, 98, 134, 130, 36, 7, 8, 135, 137, 19, + 60, 61, 62, 63, 64, 65, 139, 9, 48, 60, + 61, 62, 63, 64, 65, 21, 66, 126, 0, 142, + 0, 0, 10, 11, 12, 13, 14, 15, 0, 16, 0, 0, 0, 77, 0, 17, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 4, 5, 6, 0, 18, 0, 0, 0, 7, 8, 60, 61, 62, 63, - 64, 65, 53, 66, 19, 0, 9, 54, 55, 56, - 57, 58, 59, 76, 48, 0, 0, 0, 0, 0, + 64, 65, 0, 0, 19, 0, 9, 0, 0, 112, + 0, 0, 0, 48, 76, 0, 0, 0, 0, 0, 21, 10, 11, 12, 13, 14, 15, 0, 16, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 4, 5, 6, 0, 18, 0, 0, 0, 7, 8, 60, 61, 62, 63, 64, - 65, 0, 0, 19, 0, 9, 0, 0, 112, 0, - 0, 0, 111, 48, 0, 0, 0, 0, 0, 21, + 65, 0, 0, 19, 0, 9, 0, 0, 0, 0, + 0, 0, 48, 111, 0, 0, 0, 0, 0, 21, 10, 11, 12, 13, 14, 15, 0, 16, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 4, 5, 6, 0, 18, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 9, 0, 0, 0, 0, 0, - 0, 0, 48, 0, 0, 0, 0, 136, 21, 10, + 0, 48, 0, 0, 0, 0, 0, 136, 21, 10, 11, 12, 13, 14, 15, 0, 16, 0, 0, 0, - 0, 0, 17, 0, 0, 0, 0, 1, 0, 0, - 2, 0, 3, 4, 5, 6, 0, 18, 0, 0, - 0, 7, 8, 0, 0, 0, 0, 0, 2, 0, - 3, 19, 5, 9, 0, 0, 68, 69, 0, 7, - 8, 20, 0, 0, 0, 0, 0, 21, 10, 11, - 12, 13, 14, 15, 0, 16, 0, 0, 0, 0, - 0, 17, 0, 0, 0, 0, 0, 11, 12, 13, - 14, 15, 0, 16, 0, 0, 18, 0, 0, 17, - 2, 0, 3, 0, 5, 0, 0, 0, 0, 0, - 19, 7, 8, 0, 18, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 115, 0, 21, 0, 19, 100, - 101, 102, 103, 60, 61, 62, 63, 64, 65, 11, - 12, 13, 14, 15, 21, 16, 0, 0, 0, 0, - 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 18, 104, 105, 0, + 1, 0, 17, 2, 0, 3, 4, 5, 6, 0, + 0, 0, 51, 52, 7, 8, 2, 18, 3, 0, + 5, 0, 0, 0, 68, 69, 9, 7, 8, 0, + 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, + 20, 10, 11, 12, 13, 14, 15, 21, 16, 0, + 0, 0, 0, 0, 17, 11, 12, 13, 14, 15, + 0, 16, 2, 0, 3, 0, 5, 17, 0, 18, + 0, 0, 0, 7, 8, 0, 0, 53, 0, 0, + 0, 0, 18, 19, 54, 55, 56, 57, 58, 59, + 0, 0, 0, 0, 0, 0, 19, 115, 0, 21, + 0, 11, 12, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 21, 17, 100, 101, 102, 103, 60, 61, + 62, 63, 64, 65, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 21 + 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 104, 105, 0, 0, 0, 0, 21 }; -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-126))) - -#define yytable_value_is_error(Yytable_value) \ - YYID (0) - static const yytype_int16 yycheck[] = { - 21, 25, 20, 57, 57, 8, 7, 6, 57, 8, - 135, 7, 8, 57, 139, 100, 37, 79, 143, 43, - 62, 63, 18, 19, 80, 0, 27, 4, 79, 85, + 21, 25, 20, 7, 4, 8, 60, 60, 8, 80, + 100, 62, 63, 7, 8, 6, 37, 8, 60, 43, + 60, 92, 79, 27, 18, 19, 0, 4, 97, 98, 48, 79, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, 1, 101, 101, 4, - 99, 6, 7, 8, 9, 99, 80, 4, 79, 101, + 101, 6, 7, 8, 9, 75, 80, 99, 79, 99, 15, 16, 70, 71, 72, 73, 43, 44, 45, 46, - 4, 75, 27, 79, 8, 99, 97, 98, 81, 100, + 79, 4, 27, 79, 79, 99, 97, 98, 81, 100, 101, 102, 103, 104, 105, 106, 107, 42, 43, 44, - 45, 46, 47, 70, 49, 97, 98, 115, 79, 4, - 55, 80, 4, 4, 4, 129, 130, 84, 100, 100, - 131, 1, 73, 81, 4, 70, 6, 7, 8, 9, - 85, 63, 96, 85, 9, 15, 16, 15, 16, 84, - 68, 69, 70, 71, 72, 73, 130, 27, 98, 94, - 98, 107, 139, -1, -1, 100, 68, 69, 70, 71, - 72, 73, 42, 43, 44, 45, 46, 47, -1, 49, + 45, 46, 47, 70, 49, 80, 4, 115, 4, 4, + 55, 4, 100, 100, 135, 129, 130, 84, 139, 73, + 131, 1, 143, 81, 4, 70, 6, 7, 8, 9, + 92, 63, 92, 96, 9, 15, 16, 98, 130, 84, + 68, 69, 70, 71, 72, 73, 98, 27, 93, 68, + 69, 70, 71, 72, 73, 100, 75, 107, -1, 139, + -1, -1, 42, 43, 44, 45, 46, 47, -1, 49, -1, -1, -1, 101, -1, 55, -1, -1, -1, -1, 1, -1, -1, 4, -1, 6, 7, 8, 9, -1, 70, -1, -1, -1, 15, 16, 68, 69, 70, 71, - 72, 73, 80, 75, 84, -1, 27, 85, 86, 87, - 88, 89, 90, 93, 94, -1, -1, -1, -1, -1, + 72, 73, -1, -1, 84, -1, 27, -1, -1, 81, + -1, -1, -1, 93, 94, -1, -1, -1, -1, -1, 100, 42, 43, 44, 45, 46, 47, -1, 49, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 1, -1, -1, 4, -1, 6, 7, 8, 9, -1, 70, -1, -1, -1, 15, 16, 68, 69, 70, 71, 72, - 73, -1, -1, 84, -1, 27, -1, -1, 81, -1, + 73, -1, -1, 84, -1, 27, -1, -1, -1, -1, -1, -1, 93, 94, -1, -1, -1, -1, -1, 100, 42, 43, 44, 45, 46, 47, -1, 49, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 1, -1, -1, 4, -1, 6, 7, 8, 9, -1, 70, -1, -1, -1, 15, 16, -1, -1, -1, -1, -1, -1, -1, -1, 84, -1, 27, -1, -1, -1, -1, -1, - -1, -1, 94, -1, -1, -1, -1, 99, 100, 42, + -1, 93, -1, -1, -1, -1, -1, 99, 100, 42, 43, 44, 45, 46, 47, -1, 49, -1, -1, -1, - -1, -1, 55, -1, -1, -1, -1, 1, -1, -1, - 4, -1, 6, 7, 8, 9, -1, 70, -1, -1, - -1, 15, 16, -1, -1, -1, -1, -1, 4, -1, - 6, 84, 8, 27, -1, -1, 12, 13, -1, 15, - 16, 94, -1, -1, -1, -1, -1, 100, 42, 43, - 44, 45, 46, 47, -1, 49, -1, -1, -1, -1, - -1, 55, -1, -1, -1, -1, -1, 43, 44, 45, - 46, 47, -1, 49, -1, -1, 70, -1, -1, 55, - 4, -1, 6, -1, 8, -1, -1, -1, -1, -1, - 84, 15, 16, -1, 70, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 98, -1, 100, -1, 84, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 43, - 44, 45, 46, 47, 100, 49, -1, -1, -1, -1, - -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 70, 102, 103, -1, + 1, -1, 55, 4, -1, 6, 7, 8, 9, -1, + -1, -1, 15, 16, 15, 16, 4, 70, 6, -1, + 8, -1, -1, -1, 12, 13, 27, 15, 16, -1, + -1, 84, -1, -1, -1, -1, -1, -1, -1, -1, + 93, 42, 43, 44, 45, 46, 47, 100, 49, -1, + -1, -1, -1, -1, 55, 43, 44, 45, 46, 47, + -1, 49, 4, -1, 6, -1, 8, 55, -1, 70, + -1, -1, -1, 15, 16, -1, -1, 80, -1, -1, + -1, -1, 70, 84, 87, 88, 89, 90, 91, 92, + -1, -1, -1, -1, -1, -1, 84, 98, -1, 100, + -1, 43, 44, 45, 46, 47, -1, 49, -1, -1, + -1, -1, 100, 55, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, -1, -1, -1, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 84, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 100 + -1, -1, 84, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 102, 103, -1, -1, -1, -1, 100 }; -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 1, 4, 6, 7, 8, 9, 15, 16, 27, 42, 43, 44, 45, 46, 47, 49, 55, 70, 84, - 94, 100, 105, 106, 107, 108, 109, 111, 115, 116, + 93, 100, 105, 106, 107, 108, 109, 111, 115, 116, 117, 119, 120, 46, 116, 116, 107, 100, 79, 79, - 79, 116, 116, 108, 119, 0, 75, 4, 94, 109, - 79, 15, 16, 80, 85, 86, 87, 88, 89, 90, + 79, 116, 116, 108, 119, 0, 75, 4, 93, 109, + 79, 15, 16, 80, 87, 88, 89, 90, 91, 92, 68, 69, 70, 71, 72, 73, 75, 79, 12, 13, - 113, 114, 119, 4, 4, 4, 93, 101, 80, 85, + 113, 114, 119, 4, 4, 4, 94, 101, 80, 92, 108, 4, 8, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 4, 62, 63, 101, 64, 65, 66, 67, 102, 103, 100, 100, 8, 81, - 119, 93, 81, 114, 114, 98, 109, 110, 119, 119, - 119, 119, 119, 119, 112, 119, 112, 81, 85, 108, - 96, 57, 101, 101, 85, 98, 99, 110, 119, 98, - 117, 118, 118, 57, 99, 99, 117 + 119, 94, 81, 114, 114, 98, 109, 110, 119, 119, + 119, 119, 119, 119, 112, 119, 112, 81, 92, 108, + 96, 60, 101, 101, 92, 98, 99, 110, 119, 98, + 117, 118, 118, 60, 99, 99, 117 }; -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ - -#define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 104, 105, 106, 106, 106, 106, 106, 107, 107, + 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, + 110, 110, 111, 111, 112, 112, 112, 113, 113, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, + 115, 116, 116, 116, 116, 116, 116, 116, 117, 117, + 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 120, 120, 120, 120 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 2, 4, 5, 8, 9, 1, 2, + 1, 2, 3, 4, 1, 1, 2, 2, 5, 7, + 1, 3, 6, 6, 0, 1, 3, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, + 1, 1, 3, 3, 3, 4, 2, 2, 1, 1, + 1, 3, 1, 1, 1, 3, 3, 3, 1, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 2, 2, 2, 2 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + #define YYRECOVERING() (!!yyerrstatus) @@ -991,13 +941,13 @@ do \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) + YYERROR; \ + } \ +while (0) /* Error token number */ -#define YYTERROR 1 -#define YYERRCODE 256 +#define YYTERROR 1 +#define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. @@ -1007,7 +957,7 @@ while (YYID (0)) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ - if (YYID (N)) \ + if (N) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ @@ -1021,12 +971,27 @@ while (YYID (0)) (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ - while (YYID (0)) + while (0) #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K]) +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ @@ -1036,36 +1001,28 @@ while (YYID (0)) /* Print *YYLOCP on YYO. Private, do not rely on its existence. */ -__attribute__((__unused__)) -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +YY_ATTRIBUTE_UNUSED static unsigned yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) -#else -static unsigned -yy_location_print_ (yyo, yylocp) - FILE *yyo; - YYLTYPE const * const yylocp; -#endif { unsigned res = 0; int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; if (0 <= yylocp->first_line) { - res += fprintf (yyo, "%d", yylocp->first_line); + res += YYFPRINTF (yyo, "%d", yylocp->first_line); if (0 <= yylocp->first_column) - res += fprintf (yyo, ".%d", yylocp->first_column); + res += YYFPRINTF (yyo, ".%d", yylocp->first_column); } if (0 <= yylocp->last_line) { if (yylocp->first_line < yylocp->last_line) { - res += fprintf (yyo, "-%d", yylocp->last_line); + res += YYFPRINTF (yyo, "-%d", yylocp->last_line); if (0 <= end_col) - res += fprintf (yyo, ".%d", end_col); + res += YYFPRINTF (yyo, ".%d", end_col); } else if (0 <= end_col && yylocp->first_column < end_col) - res += fprintf (yyo, "-%d", end_col); + res += YYFPRINTF (yyo, "-%d", end_col); } return res; } @@ -1079,73 +1036,35 @@ yy_location_print_ (yyo, yylocp) #endif -/* YYLEX -- calling `yylex' with the right arguments. */ -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) -/* Enable debugging if requested. */ -#if YYDEBUG -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, Location); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; -#endif { FILE *yyo = yyoutput; YYUSE (yyo); + YYUSE (yylocationp); if (!yyvaluep) return; - YYUSE (yylocationp); # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); # endif - switch (yytype) - { - default: - break; - } + YYUSE (yytype); } @@ -1153,23 +1072,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp) | Print this symbol on YYOUTPUT. | `--------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; -#endif { - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); YY_LOCATION_PRINT (yyoutput, *yylocationp); YYFPRINTF (yyoutput, ": "); @@ -1182,16 +1089,8 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp) | TOP (included). | `------------------------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -#else -static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; -#endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) @@ -1202,50 +1101,42 @@ yy_stack_print (yybottom, yytop) YYFPRINTF (stderr, "\n"); } -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule) -#else static void -yy_reduce_print (yyvsp, yylsp, yyrule) - YYSTYPE *yyvsp; - YYLTYPE *yylsp; - int yyrule; -#endif +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule) { + unsigned long int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; - unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); + yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - , &(yylsp[(yyi + 1) - (yynrhs)]) ); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, yylsp, Rule); \ -} while (YYID (0)) +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \ +} while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ @@ -1259,7 +1150,7 @@ int yydebug; /* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH +#ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif @@ -1282,15 +1173,8 @@ int yydebug; # define yystrlen strlen # else /* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) @@ -1306,16 +1190,8 @@ yystrlen (yystr) # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif { char *yyd = yydest; const char *yys = yysrc; @@ -1345,27 +1221,27 @@ yytnamerr (char *yyres, const char *yystr) char const *yyp = yystr; for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } do_not_strip_quotes: ; } @@ -1388,11 +1264,11 @@ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { - YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ - const char *yyformat = YY_NULL; + const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per @@ -1400,10 +1276,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, int yycount = 0; /* There are many possibilities here to consider: - - Assume YYFAIL is not used. It's too flawed to consider. See - - for details. YYERROR is fine as it does not invoke this - function. - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected @@ -1453,7 +1325,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } yyarg[yycount++] = yytname[yyx]; { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; @@ -1520,33 +1392,18 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, | Release the memory associated to this symbol. | `-----------------------------------------------*/ -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) -#else -static void -yydestruct (yymsg, yytype, yyvaluep, yylocationp) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; - YYLTYPE *yylocationp; -#endif { YYUSE (yyvaluep); YYUSE (yylocationp); - if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - switch (yytype) - { - - default: - break; - } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -1555,26 +1412,14 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp) /* The lookahead symbol. */ int yychar; - -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - /* The semantic value of the lookahead symbol. */ -YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); - +YYSTYPE yylval; /* Location data for the lookahead symbol. */ YYLTYPE yylloc # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL = { 1, 1, 1, 1 } # endif ; - - /* Number of syntax errors so far. */ int yynerrs; @@ -1583,36 +1428,17 @@ int yynerrs; | yyparse. | `----------*/ -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) int yyparse (void) -#else -int -yyparse () - -#endif -#endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - `yyls': related to locations. + 'yyss': related to states. + 'yyvs': related to semantic values. + 'yyls': related to locations. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ @@ -1672,8 +1498,7 @@ yyparse () yychar = YYEMPTY; /* Cause a token to be read. */ /* User initialization code. */ -/* Line 1575 of yacc.c */ -#line 96 "../src/C.y" +#line 101 "C.y" /* yacc.c:1429 */ { #ifdef YYDEBUG #if YYDEBUG == 1 @@ -1681,8 +1506,8 @@ yyparse () #endif #endif } -/* Line 1575 of yacc.c */ -#line 1686 "dynC.tab.c" + +#line 1511 "dynC.tab.C" /* yacc.c:1429 */ yylsp[0] = yylloc; goto yysetstate; @@ -1704,26 +1529,26 @@ yyparse () #ifdef yyoverflow { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - YYLTYPE *yyls1 = yyls; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - - yyls = yyls1; - yyss = yyss1; - yyvs = yyvs1; + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE @@ -1731,23 +1556,23 @@ yyparse () # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; + goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; + yystacksize = YYMAXDEPTH; { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); - YYSTACK_RELOCATE (yyls_alloc, yyls); + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ @@ -1757,10 +1582,10 @@ yyparse () yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); + (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) - YYABORT; + YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); @@ -1789,7 +1614,7 @@ yybackup: if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; + yychar = yylex (); } if (yychar <= YYEOF) @@ -1854,7 +1679,7 @@ yyreduce: yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. + '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison @@ -1869,20 +1694,19 @@ yyreduce: switch (yyn) { case 2: -/* Line 1792 of yacc.c */ -#line 165 "../src/C.y" +#line 170 "C.y" /* yacc.c:1646 */ { oneTimeCount = 0; oneTimeGblCount = 0; if(fatalError){ parse_result = NULL; }else{ - (yyvsp[(1) - (1)].snippetList)->insert((yyvsp[(1) - (1)].snippetList)->end(), endSnippets.begin(), endSnippets.end()); - parse_result = new BPatch_sequence(*(yyvsp[(1) - (1)].snippetList)); + (yyvsp[0].snippetList)->insert((yyvsp[0].snippetList)->end(), endSnippets.begin(), endSnippets.end()); + parse_result = new BPatch_sequence(*(yyvsp[0].snippetList)); } fatalError = false; - delete (yyvsp[(1) - (1)].snippetList); + delete (yyvsp[0].snippetList); endSnippets.clear(); if(verbose) { @@ -1891,98 +1715,98 @@ yyreduce: } YYACCEPT; } +#line 1719 "dynC.tab.C" /* yacc.c:1646 */ break; case 3: -/* Line 1792 of yacc.c */ -#line 188 "../src/C.y" +#line 193 "C.y" /* yacc.c:1646 */ { std::string mangledName; - mangledName = dynC_API::mangle((yyvsp[(2) - (2)].sval), dynCSnippetName, (yyvsp[(1) - (2)].varSpec).type); + mangledName = dynC_API::mangle((yyvsp[0].sval), dynCSnippetName, (yyvsp[-1].varSpec).type); if(verbose) printf("name : %s\n", mangledName.c_str()); - (yyval.snippet) = snippetGen->findOrCreateVariable(mangledName.c_str(), (yyvsp[(1) - (2)].varSpec).type); + (yyval.snippet) = snippetGen->findOrCreateVariable(mangledName.c_str(), (yyvsp[-1].varSpec).type); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); break; } - if(!((yyvsp[(1) - (2)].varSpec).isStatic || (yyvsp[(1) - (2)].varSpec).isGlobal)){ + if(!((yyvsp[-1].varSpec).isStatic || (yyvsp[-1].varSpec).isGlobal)){ BPatch_snippet setSn = BPatch_constExpr(0); // if int etc. - if(strcmp((yyvsp[(1) - (2)].varSpec).type, "char *") == 0){ + if(strcmp((yyvsp[-1].varSpec).type, "char *") == 0){ setSn = BPatch_constExpr(""); } endSnippets.push_back(new BPatch_arithExpr(BPatch_assign, *(yyval.snippet), setSn)); } } +#line 1743 "dynC.tab.C" /* yacc.c:1646 */ break; case 4: -/* Line 1792 of yacc.c */ -#line 208 "../src/C.y" +#line 213 "C.y" /* yacc.c:1646 */ { - std::string mangledName = dynC_API::mangle((yyvsp[(2) - (4)].sval), dynCSnippetName, (yyvsp[(1) - (4)].varSpec).type); + std::string mangledName = dynC_API::mangle((yyvsp[-2].sval), dynCSnippetName, (yyvsp[-3].varSpec).type); if(verbose) printf("name : %s\n", mangledName.c_str()); - BPatch_snippet *alloc = snippetGen->findOrCreateVariable(mangledName.c_str(), (yyvsp[(1) - (4)].varSpec).type); + BPatch_snippet *alloc = snippetGen->findOrCreateVariable(mangledName.c_str(), (yyvsp[-3].varSpec).type); if(alloc == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); break; } - BPatch_arithExpr *assign = new BPatch_arithExpr(BPatch_assign, *alloc, *(yyvsp[(4) - (4)].snippet)); + BPatch_arithExpr *assign = new BPatch_arithExpr(BPatch_assign, *alloc, *(yyvsp[0].snippet)); (yyval.snippet) = assign; - if((yyvsp[(1) - (4)].varSpec).isStatic || (yyvsp[(1) - (4)].varSpec).isGlobal){ + if((yyvsp[-3].varSpec).isStatic || (yyvsp[-3].varSpec).isGlobal){ makeOneTimeStatementGbl(*(yyval.snippet)); } } +#line 1765 "dynC.tab.C" /* yacc.c:1646 */ break; case 5: -/* Line 1792 of yacc.c */ -#line 226 "../src/C.y" +#line 231 "C.y" /* yacc.c:1646 */ { //IDENTIFIER leaks, but how to fix b/c use of $0? - if((yyvsp[(4) - (5)].ival) < 0){ + if((yyvsp[-1].ival) < 0){ std::stringstream errMessage; - errMessage << "Invalid array size: " << (yyvsp[(4) - (5)].ival); + errMessage << "Invalid array size: " << (yyvsp[-1].ival); yyerrorNoTok(errMessage.str().c_str()); (yyval.snippet) = new BPatch_nullExpr(); break; } std::stringstream type; - type << (yyvsp[(1) - (5)].varSpec).type << "[" << (yyvsp[(4) - (5)].ival) << "]"; - std::string mangledName = dynC_API::mangle((yyvsp[(2) - (5)].sval), dynCSnippetName, type.str().c_str()); - (yyval.snippet) = snippetGen->findOrCreateArray(mangledName.c_str(), (yyvsp[(1) - (5)].varSpec).type, (yyvsp[(4) - (5)].ival)); + type << (yyvsp[-4].varSpec).type << "[" << (yyvsp[-1].ival) << "]"; + std::string mangledName = dynC_API::mangle((yyvsp[-3].sval), dynCSnippetName, type.str().c_str()); + (yyval.snippet) = snippetGen->findOrCreateArray(mangledName.c_str(), (yyvsp[-4].varSpec).type, (yyvsp[-1].ival)); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); break; } - if(!((yyvsp[(1) - (5)].varSpec).isStatic || (yyvsp[(1) - (5)].varSpec).isGlobal)){ + if(!((yyvsp[-4].varSpec).isStatic || (yyvsp[-4].varSpec).isGlobal)){ BPatch_snippet setSn = BPatch_constExpr(0); // if int etc. - if(strcmp((yyvsp[(1) - (5)].varSpec).type, "char *") == 0){ + if(strcmp((yyvsp[-4].varSpec).type, "char *") == 0){ setSn = BPatch_constExpr(""); } - for(int n = 0; n < (yyvsp[(4) - (5)].ival); ++n){ + for(int n = 0; n < (yyvsp[-1].ival); ++n){ endSnippets.push_back(new BPatch_arithExpr(BPatch_assign, BPatch_arithExpr(BPatch_ref, *(yyval.snippet), BPatch_constExpr(n)), setSn)); } } } +#line 1800 "dynC.tab.C" /* yacc.c:1646 */ break; case 6: -/* Line 1792 of yacc.c */ -#line 257 "../src/C.y" +#line 262 "C.y" /* yacc.c:1646 */ { std::stringstream type; - type << (yyvsp[(1) - (8)].varSpec).type << "[" << (yyvsp[(7) - (8)].snippetStringListPair)->size() << "]"; - std::string mangledName = dynC_API::mangle((yyvsp[(2) - (8)].sval), dynCSnippetName, type.str().c_str()); + type << (yyvsp[-7].varSpec).type << "[" << (yyvsp[-1].snippetStringListPair)->size() << "]"; + std::string mangledName = dynC_API::mangle((yyvsp[-6].sval), dynCSnippetName, type.str().c_str()); - (yyval.snippet) = snippetGen->findOrCreateArray(mangledName.c_str(), (yyvsp[(1) - (8)].varSpec).type, (yyvsp[(7) - (8)].snippetStringListPair)->size()); //will only allocate memory if nessessary + (yyval.snippet) = snippetGen->findOrCreateArray(mangledName.c_str(), (yyvsp[-7].varSpec).type, (yyvsp[-1].snippetStringListPair)->size()); //will only allocate memory if nessessary if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); @@ -1990,44 +1814,44 @@ yyreduce: } std::vector *assignVect = new std::vector(); assignVect->push_back((yyval.snippet)); - for(unsigned int n = 0; n < (yyvsp[(7) - (8)].snippetStringListPair)->size(); ++n){ - if(strcmp((yyvsp[(1) - (8)].varSpec).type, (*(yyvsp[(7) - (8)].snippetStringListPair))[n].second) != 0){ + for(unsigned int n = 0; n < (yyvsp[-1].snippetStringListPair)->size(); ++n){ + if(strcmp((yyvsp[-7].varSpec).type, (*(yyvsp[-1].snippetStringListPair))[n].second) != 0){ std::string errMessage = "Type conflict when trying to initialize array of type \'"; errMessage += type.str(); errMessage += "\' with a value of type "; - errMessage += (*(yyvsp[(7) - (8)].snippetStringListPair))[n].second; + errMessage += (*(yyvsp[-1].snippetStringListPair))[n].second; yyerrorNoTok(errMessage.c_str()); (yyval.snippet) = new BPatch_nullExpr(); break; } - BPatch_snippet *assign = new BPatch_arithExpr(BPatch_assign, BPatch_arithExpr(BPatch_ref, *(yyval.snippet), BPatch_constExpr(n)), *(*(yyvsp[(7) - (8)].snippetStringListPair))[n].first); + BPatch_snippet *assign = new BPatch_arithExpr(BPatch_assign, BPatch_arithExpr(BPatch_ref, *(yyval.snippet), BPatch_constExpr(n)), *(*(yyvsp[-1].snippetStringListPair))[n].first); - if((yyvsp[(1) - (8)].varSpec).isStatic || (yyvsp[(1) - (8)].varSpec).isGlobal){ + if((yyvsp[-7].varSpec).isStatic || (yyvsp[-7].varSpec).isGlobal){ makeOneTimeStatement(*assign); } assignVect->push_back(assign); } (yyval.snippet) = new BPatch_sequence(*assignVect); } +#line 1837 "dynC.tab.C" /* yacc.c:1646 */ break; case 7: -/* Line 1792 of yacc.c */ -#line 290 "../src/C.y" +#line 295 "C.y" /* yacc.c:1646 */ { std::vector argVect; std::stringstream type; - if((yyvsp[(4) - (9)].ival) < 0){ + if((yyvsp[-5].ival) < 0){ std::stringstream errMessage; - errMessage << "Invalid array size: " << (yyvsp[(4) - (9)].ival); + errMessage << "Invalid array size: " << (yyvsp[-5].ival); yyerrorNoTok(errMessage.str().c_str()); (yyval.snippet) = new BPatch_nullExpr(); break; } - type << (yyvsp[(1) - (9)].varSpec).type << "[" << (yyvsp[(4) - (9)].ival) << "]"; - std::string mangledName = dynC_API::mangle((yyvsp[(2) - (9)].sval), dynCSnippetName, type.str().c_str()); + type << (yyvsp[-8].varSpec).type << "[" << (yyvsp[-5].ival) << "]"; + std::string mangledName = dynC_API::mangle((yyvsp[-7].sval), dynCSnippetName, type.str().c_str()); - (yyval.snippet) = snippetGen->findOrCreateArray(mangledName.c_str(), (yyvsp[(1) - (9)].varSpec).type, (yyvsp[(4) - (9)].ival)); //will only allocate memory if nessessary + (yyval.snippet) = snippetGen->findOrCreateArray(mangledName.c_str(), (yyvsp[-8].varSpec).type, (yyvsp[-5].ival)); //will only allocate memory if nessessary if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); @@ -2035,23 +1859,23 @@ yyreduce: } std::vector *assignVect = new std::vector(); assignVect->push_back((yyval.snippet)); - if((unsigned int)(yyvsp[(4) - (9)].ival) != (yyvsp[(8) - (9)].snippetStringListPair)->size()){ + if((unsigned int)(yyvsp[-5].ival) != (yyvsp[-1].snippetStringListPair)->size()){ yyerrorNoTok("Invalid number of arguments given in array initialization"); (yyval.snippet) = new BPatch_nullExpr(); break; } - for(int n = 0; n < (yyvsp[(4) - (9)].ival); ++n){ - if(strcmp((yyvsp[(1) - (9)].varSpec).type, (*(yyvsp[(8) - (9)].snippetStringListPair))[n].second) != 0){ + for(int n = 0; n < (yyvsp[-5].ival); ++n){ + if(strcmp((yyvsp[-8].varSpec).type, (*(yyvsp[-1].snippetStringListPair))[n].second) != 0){ std::string errMessage = "Type conflict when trying to initialize array of type \'"; errMessage += type.str(); errMessage += "\' with a value of type "; - errMessage += (*(yyvsp[(8) - (9)].snippetStringListPair))[n].second; + errMessage += (*(yyvsp[-1].snippetStringListPair))[n].second; yyerrorNoTok(errMessage.c_str()); (yyval.snippet) = new BPatch_nullExpr(); break; } - BPatch_snippet *assign = new BPatch_arithExpr(BPatch_assign, BPatch_arithExpr(BPatch_ref, *(yyval.snippet), BPatch_constExpr(n)), *(*(yyvsp[(8) - (9)].snippetStringListPair))[n].first); - if((yyvsp[(1) - (9)].varSpec).isStatic || (yyvsp[(1) - (9)].varSpec).isGlobal){ + BPatch_snippet *assign = new BPatch_arithExpr(BPatch_assign, BPatch_arithExpr(BPatch_ref, *(yyval.snippet), BPatch_constExpr(n)), *(*(yyvsp[-1].snippetStringListPair))[n].first); + if((yyvsp[-8].varSpec).isStatic || (yyvsp[-8].varSpec).isGlobal){ makeOneTimeStatement(*assign); } assignVect->push_back(assign); @@ -2059,367 +1883,367 @@ yyreduce: } (yyval.snippet) = new BPatch_sequence(*assignVect); } +#line 1887 "dynC.tab.C" /* yacc.c:1646 */ break; case 8: -/* Line 1792 of yacc.c */ -#line 338 "../src/C.y" +#line 343 "C.y" /* yacc.c:1646 */ { - YYSTYPE::VariableSpec rSpec = {false,false,false,false,false,false,false,false,(yyvsp[(1) - (1)].sval)}; + YYSTYPE::VariableSpec rSpec = {false,false,false,false,false,false,false,false,(yyvsp[0].sval)}; (yyval.varSpec) = rSpec; } +#line 1896 "dynC.tab.C" /* yacc.c:1646 */ break; case 9: -/* Line 1792 of yacc.c */ -#line 343 "../src/C.y" +#line 348 "C.y" /* yacc.c:1646 */ { - if ((yyvsp[(2) - (2)].varSpec).isStatic){ + if ((yyvsp[0].varSpec).isStatic){ //throw error: two static yyerror("Syntax error"); }else{ - (yyvsp[(2) - (2)].varSpec).isStatic = true; + (yyvsp[0].varSpec).isStatic = true; } - (yyval.varSpec) = (yyvsp[(2) - (2)].varSpec); + (yyval.varSpec) = (yyvsp[0].varSpec); } +#line 1910 "dynC.tab.C" /* yacc.c:1646 */ break; case 10: -/* Line 1792 of yacc.c */ -#line 356 "../src/C.y" +#line 361 "C.y" /* yacc.c:1646 */ { if(verbose) printf("\n"); (yyval.snippetList) = new BPatch_Vector; - (yyval.snippetList)->push_back((yyvsp[(1) - (1)].snippet)); + (yyval.snippetList)->push_back((yyvsp[0].snippet)); } +#line 1920 "dynC.tab.C" /* yacc.c:1646 */ break; case 11: -/* Line 1792 of yacc.c */ -#line 362 "../src/C.y" +#line 367 "C.y" /* yacc.c:1646 */ { - (yyvsp[(1) - (2)].snippetList)->push_back((yyvsp[(2) - (2)].snippet)); - (yyval.snippetList) = (yyvsp[(1) - (2)].snippetList); + (yyvsp[-1].snippetList)->push_back((yyvsp[0].snippet)); + (yyval.snippetList) = (yyvsp[-1].snippetList); } +#line 1929 "dynC.tab.C" /* yacc.c:1646 */ break; case 12: -/* Line 1792 of yacc.c */ -#line 367 "../src/C.y" +#line 372 "C.y" /* yacc.c:1646 */ { - BPatch_sequence *seq = new BPatch_sequence(*(yyvsp[(2) - (3)].snippetList)); + BPatch_sequence *seq = new BPatch_sequence(*(yyvsp[-1].snippetList)); makeOneTimeStatementGbl(*seq); std::vector *retVect = new std::vector; retVect->push_back(seq); (yyval.snippetList) = retVect; } +#line 1941 "dynC.tab.C" /* yacc.c:1646 */ break; case 13: -/* Line 1792 of yacc.c */ -#line 375 "../src/C.y" +#line 380 "C.y" /* yacc.c:1646 */ { - BPatch_sequence seq = BPatch_sequence(*(yyvsp[(3) - (4)].snippetList)); + BPatch_sequence seq = BPatch_sequence(*(yyvsp[-1].snippetList)); makeOneTimeStatementGbl(seq); - (yyvsp[(1) - (4)].snippetList)->push_back(&seq); - (yyval.snippetList) = (yyvsp[(1) - (4)].snippetList); + (yyvsp[-3].snippetList)->push_back(&seq); + (yyval.snippetList) = (yyvsp[-3].snippetList); } +#line 1952 "dynC.tab.C" /* yacc.c:1646 */ break; case 14: -/* Line 1792 of yacc.c */ -#line 385 "../src/C.y" +#line 390 "C.y" /* yacc.c:1646 */ { (yyval.snippet) = new BPatch_nullExpr(); actionTaken = false; } +#line 1961 "dynC.tab.C" /* yacc.c:1646 */ break; case 15: -/* Line 1792 of yacc.c */ -#line 390 "../src/C.y" +#line 395 "C.y" /* yacc.c:1646 */ { - yyerrorNoTok((yyvsp[(1) - (1)].context)); + yyerrorNoTok((yyvsp[0].context)); (yyval.snippet) = new BPatch_nullExpr(); actionTaken = false; } +#line 1971 "dynC.tab.C" /* yacc.c:1646 */ break; case 16: -/* Line 1792 of yacc.c */ -#line 396 "../src/C.y" +#line 401 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = (yyvsp[(1) - (2)].snippet); + (yyval.snippet) = (yyvsp[-1].snippet); } +#line 1979 "dynC.tab.C" /* yacc.c:1646 */ break; case 17: -/* Line 1792 of yacc.c */ -#line 401 "../src/C.y" +#line 406 "C.y" /* yacc.c:1646 */ { if(!actionTaken){ yywarn("Statement does nothing!"); (yyval.snippet) = new BPatch_nullExpr(); }else{ - (yyval.snippet) = (yyvsp[(1) - (2)].snippet); + (yyval.snippet) = (yyvsp[-1].snippet); } actionTaken = false; } +#line 1993 "dynC.tab.C" /* yacc.c:1646 */ break; case 18: -/* Line 1792 of yacc.c */ -#line 412 "../src/C.y" +#line 417 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" if () "); - (yyval.snippet) = new BPatch_ifExpr(*(yyvsp[(3) - (5)].boolExpr), *(yyvsp[(5) - (5)].snippet)); - delete (yyvsp[(3) - (5)].boolExpr); - delete (yyvsp[(5) - (5)].snippet); + (yyval.snippet) = new BPatch_ifExpr(*(yyvsp[-2].boolExpr), *(yyvsp[0].snippet)); + delete (yyvsp[-2].boolExpr); + delete (yyvsp[0].snippet); } +#line 2004 "dynC.tab.C" /* yacc.c:1646 */ break; case 19: -/* Line 1792 of yacc.c */ -#line 420 "../src/C.y" +#line 425 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" if () else "); - (yyval.snippet) = new BPatch_ifExpr(*(yyvsp[(3) - (7)].boolExpr), *(yyvsp[(5) - (7)].snippet), *(yyvsp[(7) - (7)].snippet)); - delete (yyvsp[(3) - (7)].boolExpr); - delete (yyvsp[(5) - (7)].snippet); - delete (yyvsp[(7) - (7)].snippet); + (yyval.snippet) = new BPatch_ifExpr(*(yyvsp[-4].boolExpr), *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); + delete (yyvsp[-4].boolExpr); + delete (yyvsp[-2].snippet); + delete (yyvsp[0].snippet); } +#line 2016 "dynC.tab.C" /* yacc.c:1646 */ break; case 21: -/* Line 1792 of yacc.c */ -#line 433 "../src/C.y" +#line 438 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = new BPatch_sequence(*(yyvsp[(2) - (3)].snippetList)); - delete (yyvsp[(2) - (3)].snippetList); + (yyval.snippet) = new BPatch_sequence(*(yyvsp[-1].snippetList)); + delete (yyvsp[-1].snippetList); } +#line 2025 "dynC.tab.C" /* yacc.c:1646 */ break; case 22: -/* Line 1792 of yacc.c */ -#line 440 "../src/C.y" +#line 445 "C.y" /* yacc.c:1646 */ { - if(strcmp((yyvsp[(3) - (6)].sval), "break") == 0){ + if(strcmp((yyvsp[-3].sval), "break") == 0){ if(verbose) printf("break_ ()"); (yyval.snippet) = new BPatch_breakPointExpr(); }else{ - char *errString = (char *)calloc(strlen((yyvsp[(3) - (6)].sval)), sizeof(char)); - sprintf(errString, "%s not found!\n", (yyvsp[(3) - (6)].sval)); + char *errString = (char *)calloc(strlen((yyvsp[-3].sval)), sizeof(char)); + sprintf(errString, "%s not found!\n", (yyvsp[-3].sval)); yyerror(errString); (yyval.snippet) = new BPatch_nullExpr(); free(errString); } - delete (yyvsp[(3) - (6)].sval); + delete (yyvsp[-3].sval); } +#line 2043 "dynC.tab.C" /* yacc.c:1646 */ break; case 23: -/* Line 1792 of yacc.c */ -#line 456 "../src/C.y" +#line 461 "C.y" /* yacc.c:1646 */ { - BPatch_function *func = snippetGen->findFunction((yyvsp[(3) - (6)].sval), *(yyvsp[(5) - (6)].snippetList)); + BPatch_function *func = snippetGen->findFunction((yyvsp[-3].sval), *(yyvsp[-1].snippetList)); if(func == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerrorNoTok(snippetGen->getError().c_str()); break; } - (yyval.snippet) = new BPatch_funcCallExpr(*func, *(yyvsp[(5) - (6)].snippetList)); + (yyval.snippet) = new BPatch_funcCallExpr(*func, *(yyvsp[-1].snippetList)); } +#line 2057 "dynC.tab.C" /* yacc.c:1646 */ break; case 24: -/* Line 1792 of yacc.c */ -#line 469 "../src/C.y" +#line 474 "C.y" /* yacc.c:1646 */ { //No parameters, return an empty vector (yyval.snippetList) = new BPatch_Vector; } +#line 2066 "dynC.tab.C" /* yacc.c:1646 */ break; case 25: -/* Line 1792 of yacc.c */ -#line 475 "../src/C.y" +#line 480 "C.y" /* yacc.c:1646 */ { (yyval.snippetList) = new BPatch_Vector; - (yyval.snippetList)->push_back((yyvsp[(1) - (1)].snippet)); + (yyval.snippetList)->push_back((yyvsp[0].snippet)); } +#line 2075 "dynC.tab.C" /* yacc.c:1646 */ break; case 26: -/* Line 1792 of yacc.c */ -#line 481 "../src/C.y" +#line 486 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" , "); - (yyvsp[(1) - (3)].snippetList)->push_back((yyvsp[(3) - (3)].snippet)); - (yyval.snippetList) = (yyvsp[(1) - (3)].snippetList); + (yyvsp[-2].snippetList)->push_back((yyvsp[0].snippet)); + (yyval.snippetList) = (yyvsp[-2].snippetList); } +#line 2085 "dynC.tab.C" /* yacc.c:1646 */ break; case 27: -/* Line 1792 of yacc.c */ -#line 490 "../src/C.y" +#line 495 "C.y" /* yacc.c:1646 */ { (yyval.boolExpr) = new BPatch_boolExpr(BPatch_eq, BPatch_constExpr(0), BPatch_constExpr(0)); } +#line 2093 "dynC.tab.C" /* yacc.c:1646 */ break; case 28: -/* Line 1792 of yacc.c */ -#line 494 "../src/C.y" +#line 499 "C.y" /* yacc.c:1646 */ { (yyval.boolExpr) = new BPatch_boolExpr(BPatch_ne, BPatch_constExpr(0), BPatch_constExpr(0)); } +#line 2101 "dynC.tab.C" /* yacc.c:1646 */ break; case 30: -/* Line 1792 of yacc.c */ -#line 502 "../src/C.y" +#line 507 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" < "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_lt, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_lt, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); } +#line 2110 "dynC.tab.C" /* yacc.c:1646 */ break; case 31: -/* Line 1792 of yacc.c */ -#line 507 "../src/C.y" +#line 512 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" > "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_gt, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_gt, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); } +#line 2119 "dynC.tab.C" /* yacc.c:1646 */ break; case 32: -/* Line 1792 of yacc.c */ -#line 512 "../src/C.y" +#line 517 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" == "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_eq, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_eq, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); } +#line 2128 "dynC.tab.C" /* yacc.c:1646 */ break; case 33: -/* Line 1792 of yacc.c */ -#line 517 "../src/C.y" +#line 522 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" <= "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_le, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_le, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); } +#line 2137 "dynC.tab.C" /* yacc.c:1646 */ break; case 34: -/* Line 1792 of yacc.c */ -#line 522 "../src/C.y" +#line 527 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" >= "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_ge, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_ge, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); } +#line 2146 "dynC.tab.C" /* yacc.c:1646 */ break; case 35: -/* Line 1792 of yacc.c */ -#line 527 "../src/C.y" +#line 532 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" != "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_ne, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_ne, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); } +#line 2155 "dynC.tab.C" /* yacc.c:1646 */ break; case 36: -/* Line 1792 of yacc.c */ -#line 532 "../src/C.y" +#line 537 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" AND "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_and, *(yyvsp[(1) - (3)].boolExpr), *(yyvsp[(3) - (3)].boolExpr)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_and, *(yyvsp[-2].boolExpr), *(yyvsp[0].boolExpr)); } +#line 2164 "dynC.tab.C" /* yacc.c:1646 */ break; case 37: -/* Line 1792 of yacc.c */ -#line 537 "../src/C.y" +#line 542 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" OR "); - (yyval.boolExpr) = new BPatch_boolExpr(BPatch_or, *(yyvsp[(1) - (3)].boolExpr), *(yyvsp[(3) - (3)].boolExpr)); + (yyval.boolExpr) = new BPatch_boolExpr(BPatch_or, *(yyvsp[-2].boolExpr), *(yyvsp[0].boolExpr)); } +#line 2172 "dynC.tab.C" /* yacc.c:1646 */ break; case 38: -/* Line 1792 of yacc.c */ -#line 545 "../src/C.y" +#line 550 "C.y" /* yacc.c:1646 */ { YYSTYPE::VariableSpec vSpec = {false,false,false,false,false,false,false,false,""}; vSpec.isGlobal = true; (yyval.varSpec) = vSpec; } +#line 2182 "dynC.tab.C" /* yacc.c:1646 */ break; case 39: -/* Line 1792 of yacc.c */ -#line 551 "../src/C.y" +#line 556 "C.y" /* yacc.c:1646 */ { YYSTYPE::VariableSpec vSpec = {false,false,false,false,false,false,false,false,""}; vSpec.isLocal = true; (yyval.varSpec) = vSpec; } +#line 2192 "dynC.tab.C" /* yacc.c:1646 */ break; case 40: -/* Line 1792 of yacc.c */ -#line 557 "../src/C.y" +#line 562 "C.y" /* yacc.c:1646 */ { YYSTYPE::VariableSpec vSpec = {false,false,false,false,false,false,false,false,""}; vSpec.isParam = true; (yyval.varSpec) = vSpec; } +#line 2202 "dynC.tab.C" /* yacc.c:1646 */ break; case 41: -/* Line 1792 of yacc.c */ -#line 566 "../src/C.y" +#line 571 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = snippetGen->findInstVariable(dynC_API::getMangledStub((yyvsp[(1) - (1)].sval), dynCSnippetName).c_str(), (yyvsp[(1) - (1)].sval)); + (yyval.snippet) = snippetGen->findInstVariable(dynC_API::getMangledStub((yyvsp[0].sval), dynCSnippetName).c_str(), (yyvsp[0].sval)); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); break; } } +#line 2215 "dynC.tab.C" /* yacc.c:1646 */ break; case 42: -/* Line 1792 of yacc.c */ -#line 575 "../src/C.y" +#line 580 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = snippetGen->findAppVariable((yyvsp[(3) - (3)].sval)); + (yyval.snippet) = snippetGen->findAppVariable((yyvsp[0].sval)); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerrorNoTokNonUni(snippetGen->getError().c_str()); break; } } +#line 2228 "dynC.tab.C" /* yacc.c:1646 */ break; case 43: -/* Line 1792 of yacc.c */ -#line 585 "../src/C.y" +#line 590 "C.y" /* yacc.c:1646 */ { //disallowed if there is no point specifier - if(!(yyvsp[(1) - (3)].varSpec).isGlobal && snippetPoint == NULL){ + if(!(yyvsp[-2].varSpec).isGlobal && snippetPoint == NULL){ yyerrorNoTok("Local variables not allowed when snippet point is unspecified."); YYABORT; break; } - if((yyvsp[(1) - (3)].varSpec).isParam){ - (yyval.snippet) = snippetGen->findParameter((yyvsp[(3) - (3)].sval)); + if((yyvsp[-2].varSpec).isParam){ + (yyval.snippet) = snippetGen->findParameter((yyvsp[0].sval)); }else{ - (yyval.snippet) = snippetGen->findAppVariable((yyvsp[(3) - (3)].sval), (yyvsp[(1) - (3)].varSpec).isGlobal, (yyvsp[(1) - (3)].varSpec).isLocal); + (yyval.snippet) = snippetGen->findAppVariable((yyvsp[0].sval), (yyvsp[-2].varSpec).isGlobal, (yyvsp[-2].varSpec).isLocal); } if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); - if((yyvsp[(1) - (3)].varSpec).isGlobal){ + if((yyvsp[-2].varSpec).isGlobal){ yyerror(snippetGen->getError().c_str()); YYABORT; }else{ @@ -2429,134 +2253,134 @@ yyreduce: break; } } +#line 2257 "dynC.tab.C" /* yacc.c:1646 */ break; case 44: -/* Line 1792 of yacc.c */ -#line 611 "../src/C.y" +#line 616 "C.y" /* yacc.c:1646 */ { //special case for indexed parameters if(snippetPoint == NULL){ yyerrorNoTok("Local variables not allowed when snippet point is unspecified."); break; } - if(!(yyvsp[(1) - (3)].varSpec).isParam){ + if(!(yyvsp[-2].varSpec).isParam){ yyerror("Numbered indexes for parameters only"); (yyval.snippet) = new BPatch_nullExpr(); break; } - (yyval.snippet) = snippetGen->findParameter((yyvsp[(3) - (3)].ival)); + (yyval.snippet) = snippetGen->findParameter((yyvsp[0].ival)); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerrorNoTokNonUni(snippetGen->getError().c_str()); break; } } +#line 2280 "dynC.tab.C" /* yacc.c:1646 */ break; case 45: -/* Line 1792 of yacc.c */ -#line 631 "../src/C.y" +#line 636 "C.y" /* yacc.c:1646 */ { //array referance //check for integer in arith_expression - (yyval.snippet) = snippetGen->generateArrayRef((yyvsp[(1) - (4)].snippet), (yyvsp[(3) - (4)].snippet)); + (yyval.snippet) = snippetGen->generateArrayRef((yyvsp[-3].snippet), (yyvsp[-1].snippet)); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); break; } } +#line 2295 "dynC.tab.C" /* yacc.c:1646 */ break; case 46: -/* Line 1792 of yacc.c */ -#line 642 "../src/C.y" +#line 647 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = (BPatch_snippet *)(new BPatch_arithExpr(BPatch_deref, *(yyvsp[(2) - (2)].snippet))); + (yyval.snippet) = (BPatch_snippet *)(new BPatch_arithExpr(BPatch_deref, *(yyvsp[0].snippet))); } +#line 2303 "dynC.tab.C" /* yacc.c:1646 */ break; case 47: -/* Line 1792 of yacc.c */ -#line 646 "../src/C.y" +#line 651 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = (BPatch_snippet *)(new BPatch_arithExpr(BPatch_addr, *(yyvsp[(2) - (2)].snippet))); + (yyval.snippet) = (BPatch_snippet *)(new BPatch_arithExpr(BPatch_addr, *(yyvsp[0].snippet))); } +#line 2311 "dynC.tab.C" /* yacc.c:1646 */ break; case 48: -/* Line 1792 of yacc.c */ -#line 653 "../src/C.y" +#line 658 "C.y" /* yacc.c:1646 */ { - if(verbose) printf(" %d ", (yyvsp[(1) - (1)].ival)); - BPatch_snippet * c = new BPatch_constExpr((yyvsp[(1) - (1)].ival)); + if(verbose) printf(" %d ", (yyvsp[0].ival)); + BPatch_snippet * c = new BPatch_constExpr((yyvsp[0].ival)); (yyval.snippetStringPair) = new std::pair(c, "int"); } +#line 2321 "dynC.tab.C" /* yacc.c:1646 */ break; case 49: -/* Line 1792 of yacc.c */ -#line 659 "../src/C.y" +#line 664 "C.y" /* yacc.c:1646 */ { - if(verbose) printf(" %s ", (yyvsp[(1) - (1)].sval)); - BPatch_snippet * c = new BPatch_constExpr((yyvsp[(1) - (1)].sval)); + if(verbose) printf(" %s ", (yyvsp[0].sval)); + BPatch_snippet * c = new BPatch_constExpr((yyvsp[0].sval)); (yyval.snippetStringPair) = new std::pair(c, "char *"); } +#line 2331 "dynC.tab.C" /* yacc.c:1646 */ break; case 50: -/* Line 1792 of yacc.c */ -#line 668 "../src/C.y" +#line 673 "C.y" /* yacc.c:1646 */ { std::vector > *cnlist = new std::vector >(); - cnlist->push_back(*(yyvsp[(1) - (1)].snippetStringPair)); + cnlist->push_back(*(yyvsp[0].snippetStringPair)); (yyval.snippetStringListPair) = cnlist; } +#line 2341 "dynC.tab.C" /* yacc.c:1646 */ break; case 51: -/* Line 1792 of yacc.c */ -#line 674 "../src/C.y" +#line 679 "C.y" /* yacc.c:1646 */ { - (yyvsp[(1) - (3)].snippetStringListPair)->push_back(*(yyvsp[(3) - (3)].snippetStringPair)); - (yyval.snippetStringListPair) = (yyvsp[(1) - (3)].snippetStringListPair); + (yyvsp[-2].snippetStringListPair)->push_back(*(yyvsp[0].snippetStringPair)); + (yyval.snippetStringListPair) = (yyvsp[-2].snippetStringListPair); } +#line 2350 "dynC.tab.C" /* yacc.c:1646 */ break; case 53: -/* Line 1792 of yacc.c */ -#line 680 "../src/C.y" - {(yyval.snippet) = (yyvsp[(1) - (1)].snippetStringPair)->first;} +#line 685 "C.y" /* yacc.c:1646 */ + {(yyval.snippet) = (yyvsp[0].snippetStringPair)->first;} +#line 2356 "dynC.tab.C" /* yacc.c:1646 */ break; case 54: -/* Line 1792 of yacc.c */ -#line 681 "../src/C.y" +#line 686 "C.y" /* yacc.c:1646 */ {(yyval.snippet) = new BPatch_nullExpr();} +#line 2362 "dynC.tab.C" /* yacc.c:1646 */ break; case 55: -/* Line 1792 of yacc.c */ -#line 683 "../src/C.y" +#line 688 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = snippetGen->findRegister((yyvsp[(3) - (3)].sval)); + (yyval.snippet) = snippetGen->findRegister((yyvsp[0].sval)); if ((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); yyerror(snippetGen->getError().c_str()); } } +#line 2374 "dynC.tab.C" /* yacc.c:1646 */ break; case 56: -/* Line 1792 of yacc.c */ -#line 692 "../src/C.y" +#line 697 "C.y" /* yacc.c:1646 */ { - if(verbose) printf("dyninst`%s ", (yyvsp[(3) - (3)].sval)); + if(verbose) printf("dyninst`%s ", (yyvsp[0].sval)); std::vector argVect; //snippets w/ return vals - if(strcmp((yyvsp[(3) - (3)].sval), "function_name") == 0){ + if(strcmp((yyvsp[0].sval), "function_name") == 0){ (yyval.snippet) = snippetGen->getContextInfo(SnippetGenerator::SG_FunctionName); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); @@ -2564,7 +2388,7 @@ yyreduce: } break; } - if(strcmp((yyvsp[(3) - (3)].sval), "module_name") == 0){ + if(strcmp((yyvsp[0].sval), "module_name") == 0){ (yyval.snippet) = snippetGen->getContextInfo(SnippetGenerator::SG_ModuleName); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); @@ -2572,24 +2396,24 @@ yyreduce: } break; } - if(strcmp((yyvsp[(3) - (3)].sval), "bytes_accessed") == 0){ + if(strcmp((yyvsp[0].sval), "bytes_accessed") == 0){ (yyval.snippet) = new BPatch_bytesAccessedExpr(); break; } - if(strcmp((yyvsp[(3) - (3)].sval), "effective_address") == 0){ + if(strcmp((yyvsp[0].sval), "effective_address") == 0){ (yyval.snippet) = new BPatch_effectiveAddressExpr(); break; } - if(strcmp((yyvsp[(3) - (3)].sval), "original_address") == 0){ + if(strcmp((yyvsp[0].sval), "original_address") == 0){ (yyval.snippet) = new BPatch_originalAddressExpr(); break; } - if(strcmp((yyvsp[(3) - (3)].sval), "actual_address") == 0){ + if(strcmp((yyvsp[0].sval), "actual_address") == 0){ (yyval.snippet) = new BPatch_actualAddressExpr(); break; } - if(strcmp((yyvsp[(3) - (3)].sval), "return_value") == 0){ + if(strcmp((yyvsp[0].sval), "return_value") == 0){ if(snippetGen->getPoint()->getPointType() != BPatch_exit){ (yyval.snippet) = new BPatch_nullExpr(); yyerrorNoTokNonUni("Return values only valid at function exit points"); @@ -2598,11 +2422,11 @@ yyreduce: (yyval.snippet) = new BPatch_retExpr(); break; } - if(strcmp((yyvsp[(3) - (3)].sval), "thread_index") == 0){ + if(strcmp((yyvsp[0].sval), "thread_index") == 0){ (yyval.snippet) = new BPatch_threadIndexExpr(); break; } - if(strcmp((yyvsp[(3) - (3)].sval), "tid") == 0){ + if(strcmp((yyvsp[0].sval), "tid") == 0){ (yyval.snippet) = snippetGen->getContextInfo(SnippetGenerator::SG_TID); if((yyval.snippet) == NULL){ (yyval.snippet) = new BPatch_nullExpr(); @@ -2610,7 +2434,7 @@ yyreduce: } break; } - if(strcmp((yyvsp[(3) - (3)].sval), "dynamic_target") == 0){ + if(strcmp((yyvsp[0].sval), "dynamic_target") == 0){ (yyval.snippet) = new BPatch_dynamicTargetExpr(); break; } @@ -2618,198 +2442,198 @@ yyreduce: yyerror("Syntax error: unrecognized dyninst call"); (yyval.snippet) = new BPatch_nullExpr(); } +#line 2446 "dynC.tab.C" /* yacc.c:1646 */ break; case 57: -/* Line 1792 of yacc.c */ -#line 760 "../src/C.y" +#line 765 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" * "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_times, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.snippet) = new BPatch_arithExpr(BPatch_times, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); actionTaken = true; } +#line 2456 "dynC.tab.C" /* yacc.c:1646 */ break; case 58: -/* Line 1792 of yacc.c */ -#line 766 "../src/C.y" +#line 771 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = (yyvsp[(1) - (1)].snippet); + (yyval.snippet) = (yyvsp[0].snippet); actionTaken = true; } +#line 2465 "dynC.tab.C" /* yacc.c:1646 */ break; case 59: -/* Line 1792 of yacc.c */ -#line 771 "../src/C.y" +#line 776 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" = "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); actionTaken = true; } +#line 2475 "dynC.tab.C" /* yacc.c:1646 */ break; case 60: -/* Line 1792 of yacc.c */ -#line 777 "../src/C.y" +#line 782 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" += "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (3)].snippet), BPatch_arithExpr(BPatch_plus, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[-2].snippet), BPatch_arithExpr(BPatch_plus, *(yyvsp[-2].snippet), *(yyvsp[0].snippet))); actionTaken = true; } +#line 2485 "dynC.tab.C" /* yacc.c:1646 */ break; case 61: -/* Line 1792 of yacc.c */ -#line 783 "../src/C.y" +#line 788 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" -= "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (3)].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[-2].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[-2].snippet), *(yyvsp[0].snippet))); actionTaken = true; } +#line 2495 "dynC.tab.C" /* yacc.c:1646 */ break; case 62: -/* Line 1792 of yacc.c */ -#line 789 "../src/C.y" +#line 794 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" *= "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (3)].snippet), BPatch_arithExpr(BPatch_times, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[-2].snippet), BPatch_arithExpr(BPatch_times, *(yyvsp[-2].snippet), *(yyvsp[0].snippet))); actionTaken = true; } +#line 2505 "dynC.tab.C" /* yacc.c:1646 */ break; case 63: -/* Line 1792 of yacc.c */ -#line 795 "../src/C.y" +#line 800 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" /= "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (3)].snippet), BPatch_arithExpr(BPatch_divide, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[-2].snippet), BPatch_arithExpr(BPatch_divide, *(yyvsp[-2].snippet), *(yyvsp[0].snippet))); actionTaken = true; } +#line 2515 "dynC.tab.C" /* yacc.c:1646 */ break; case 64: -/* Line 1792 of yacc.c */ -#line 801 "../src/C.y" +#line 806 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" %%= "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (3)].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[(1) - (3)].snippet), BPatch_arithExpr(BPatch_times, BPatch_arithExpr(BPatch_divide, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)), *(yyvsp[(3) - (3)].snippet)))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_assign, *(yyvsp[-2].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[-2].snippet), BPatch_arithExpr(BPatch_times, BPatch_arithExpr(BPatch_divide, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)), *(yyvsp[0].snippet)))); actionTaken = true; } +#line 2525 "dynC.tab.C" /* yacc.c:1646 */ break; case 65: -/* Line 1792 of yacc.c */ -#line 807 "../src/C.y" +#line 812 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" / "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_divide, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.snippet) = new BPatch_arithExpr(BPatch_divide, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); actionTaken = true; } +#line 2535 "dynC.tab.C" /* yacc.c:1646 */ break; case 66: -/* Line 1792 of yacc.c */ -#line 813 "../src/C.y" +#line 818 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" %% "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_minus, *(yyvsp[(1) - (3)].snippet), BPatch_arithExpr(BPatch_times, BPatch_arithExpr(BPatch_divide, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)), *(yyvsp[(3) - (3)].snippet))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_minus, *(yyvsp[-2].snippet), BPatch_arithExpr(BPatch_times, BPatch_arithExpr(BPatch_divide, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)), *(yyvsp[0].snippet))); actionTaken = true; } +#line 2545 "dynC.tab.C" /* yacc.c:1646 */ break; case 67: -/* Line 1792 of yacc.c */ -#line 819 "../src/C.y" +#line 824 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" + "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_plus, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.snippet) = new BPatch_arithExpr(BPatch_plus, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); actionTaken = true; } +#line 2555 "dynC.tab.C" /* yacc.c:1646 */ break; case 68: -/* Line 1792 of yacc.c */ -#line 825 "../src/C.y" +#line 830 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" - "); - (yyval.snippet) = new BPatch_arithExpr(BPatch_minus, *(yyvsp[(1) - (3)].snippet), *(yyvsp[(3) - (3)].snippet)); + (yyval.snippet) = new BPatch_arithExpr(BPatch_minus, *(yyvsp[-2].snippet), *(yyvsp[0].snippet)); actionTaken = true; } +#line 2565 "dynC.tab.C" /* yacc.c:1646 */ break; case 69: -/* Line 1792 of yacc.c */ -#line 831 "../src/C.y" +#line 836 "C.y" /* yacc.c:1646 */ { - if(dynamic_cast((yyvsp[(1) - (3)].snippet))){ + if(dynamic_cast((yyvsp[-2].snippet))){ printf("Picked second\n"); - (yyval.snippet) = (yyvsp[(3) - (3)].snippet); + (yyval.snippet) = (yyvsp[0].snippet); }else{ - (yyval.snippet) = (yyvsp[(1) - (3)].snippet); + (yyval.snippet) = (yyvsp[-2].snippet); } } +#line 2578 "dynC.tab.C" /* yacc.c:1646 */ break; case 70: -/* Line 1792 of yacc.c */ -#line 839 "../src/C.y" - {(yyval.snippet) = (yyvsp[(2) - (3)].snippet);} +#line 844 "C.y" /* yacc.c:1646 */ + {(yyval.snippet) = (yyvsp[-1].snippet);} +#line 2584 "dynC.tab.C" /* yacc.c:1646 */ break; case 71: -/* Line 1792 of yacc.c */ -#line 841 "../src/C.y" +#line 846 "C.y" /* yacc.c:1646 */ { - (yyval.snippet) = (yyvsp[(1) - (1)].snippet); + (yyval.snippet) = (yyvsp[0].snippet); actionTaken = true; } +#line 2593 "dynC.tab.C" /* yacc.c:1646 */ break; case 72: -/* Line 1792 of yacc.c */ -#line 850 "../src/C.y" +#line 855 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" ++ "); - BPatch_arithExpr addOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (2)].snippet), BPatch_arithExpr(BPatch_plus, *(yyvsp[(1) - (2)].snippet), BPatch_constExpr(1))); - (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)addOne, BPatch_arithExpr(BPatch_minus, *(yyvsp[(1) - (2)].snippet), BPatch_constExpr(1))); + BPatch_arithExpr addOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[-1].snippet), BPatch_arithExpr(BPatch_plus, *(yyvsp[-1].snippet), BPatch_constExpr(1))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)addOne, BPatch_arithExpr(BPatch_minus, *(yyvsp[-1].snippet), BPatch_constExpr(1))); } +#line 2603 "dynC.tab.C" /* yacc.c:1646 */ break; case 73: -/* Line 1792 of yacc.c */ -#line 856 "../src/C.y" +#line 861 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" ++ "); - BPatch_arithExpr addOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[(2) - (2)].snippet), BPatch_arithExpr(BPatch_plus, *(yyvsp[(2) - (2)].snippet), BPatch_constExpr(1))); - (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)addOne, *(yyvsp[(2) - (2)].snippet)); + BPatch_arithExpr addOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[0].snippet), BPatch_arithExpr(BPatch_plus, *(yyvsp[0].snippet), BPatch_constExpr(1))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)addOne, *(yyvsp[0].snippet)); } +#line 2613 "dynC.tab.C" /* yacc.c:1646 */ break; case 74: -/* Line 1792 of yacc.c */ -#line 862 "../src/C.y" +#line 867 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" -- "); - BPatch_arithExpr subOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[(1) - (2)].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[(1) - (2)].snippet), BPatch_constExpr(1))); - (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)subOne, BPatch_arithExpr(BPatch_plus, *(yyvsp[(1) - (2)].snippet), BPatch_constExpr(1))); + BPatch_arithExpr subOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[-1].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[-1].snippet), BPatch_constExpr(1))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)subOne, BPatch_arithExpr(BPatch_plus, *(yyvsp[-1].snippet), BPatch_constExpr(1))); } +#line 2623 "dynC.tab.C" /* yacc.c:1646 */ break; case 75: -/* Line 1792 of yacc.c */ -#line 868 "../src/C.y" +#line 873 "C.y" /* yacc.c:1646 */ { if(verbose) printf(" -- "); - BPatch_arithExpr subOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[(2) - (2)].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[(2) - (2)].snippet), BPatch_constExpr(1))); - (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)subOne, *(yyvsp[(2) - (2)].snippet)); + BPatch_arithExpr subOne = BPatch_arithExpr(BPatch_assign, *(yyvsp[0].snippet), BPatch_arithExpr(BPatch_minus, *(yyvsp[0].snippet), BPatch_constExpr(1))); + (yyval.snippet) = new BPatch_arithExpr(BPatch_seq, (BPatch_snippet &)subOne, *(yyvsp[0].snippet)); } +#line 2633 "dynC.tab.C" /* yacc.c:1646 */ break; -/* Line 1792 of yacc.c */ -#line 2813 "dynC.tab.c" +#line 2637 "dynC.tab.C" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -2832,7 +2656,7 @@ yyreduce: *++yyvsp = yyval; *++yylsp = yyloc; - /* Now `shift' the result of the reduction. Determine what state + /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ @@ -2847,9 +2671,9 @@ yyreduce: goto yynewstate; -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ @@ -2900,20 +2724,20 @@ yyerrlab: if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an - error, discard it. */ + error, discard it. */ if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } else - { - yydestruct ("Error: discarding", - yytoken, &yylval, &yylloc); - yychar = YYEMPTY; - } + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc); + yychar = YYEMPTY; + } } /* Else will try to reuse lookahead token after shifting the error @@ -2933,7 +2757,7 @@ yyerrorlab: goto yyerrorlab; yyerror_range[1] = yylsp[1-yylen]; - /* Do not reclaim the symbols of the rule which action triggered + /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; @@ -2946,29 +2770,29 @@ yyerrorlab: | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ + yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) - YYABORT; + YYABORT; yyerror_range[1] = *yylsp; yydestruct ("Error: popping", - yystos[yystate], yyvsp, yylsp); + yystos[yystate], yyvsp, yylsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); @@ -3024,14 +2848,14 @@ yyreturn: yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc); } - /* Do not reclaim the symbols of the rule which action triggered + /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, yylsp); + yystos[*yyssp], yyvsp, yylsp); YYPOPSTACK (1); } #ifndef yyoverflow @@ -3042,13 +2866,9 @@ yyreturn: if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif - /* Make sure YYID is used. */ - return YYID (yyresult); + return yyresult; } - - -/* Line 2055 of yacc.c */ -#line 875 "../src/C.y" +#line 880 "C.y" /* yacc.c:1906 */ #include diff --git a/dynC_API/src/dynC.tab.h b/dynC_API/src/dynC.tab.h index 78ae563a95..5905d95443 100644 --- a/dynC_API/src/dynC.tab.h +++ b/dynC_API/src/dynC.tab.h @@ -1,19 +1,19 @@ -/* A Bison parser, made by GNU Bison 2.7. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. - + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program 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 General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -26,13 +26,13 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_DYNC_DYNC_TAB_H_INCLUDED # define YY_DYNC_DYNC_TAB_H_INCLUDED -/* Enabling traces. */ +/* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif @@ -40,105 +40,104 @@ extern int dynCdebug; #endif -/* Tokens. */ +/* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - KNOWN_ERROR_TOK = 258, - IDENTIFIER = 259, - CONSTANT = 260, - STRING = 261, - TYPE = 262, - NUMBER = 263, - ERROR = 264, - EOL = 265, - SIZEOF = 266, - D_TRUE = 267, - D_FALSE = 268, - PTR_OP = 269, - INC_OP = 270, - DEC_OP = 271, - LEFT_OP = 272, - RIGHT_OP = 273, - LEFT_ASSIGN = 274, - RIGHT_ASSIGN = 275, - AND_ASSIGN = 276, - XOR_ASSIGN = 277, - OR_ASSIGN = 278, - TYPE_NAME = 279, - TYPEDEF = 280, - EXTERN = 281, - STATIC = 282, - CHAR = 283, - SHORT = 284, - INT = 285, - LONG = 286, - SIGNED = 287, - UNSIGNED = 288, - FLOAT = 289, - DOUBLE = 290, - CONST = 291, - VOID = 292, - STRUCT = 293, - UNION = 294, - ENUM = 295, - ELLIPSIS = 296, - IF = 297, - LOCAL = 298, - PARAM = 299, - GLOBAL = 300, - FUNC = 301, - DYNINST = 302, - INST = 303, - REGISTER = 304, - NEWLINE = 305, - CASE = 306, - DEFAULT = 307, - SWITCH = 308, - RETURN = 309, - NILL = 310, - EOF_TOK = 311, - COMMA = 312, - AMPERSAND = 313, - ASTERISK = 314, - DOT = 315, - NOT = 316, - OR = 317, - AND = 318, - NOT_EQ = 319, - EQ = 320, - GREATER_EQ = 321, - LESS_EQ = 322, - COLON = 323, - SEMI = 324, - END_BLOCK = 325, - START_BLOCK = 326, - DOLLAR = 327, - BACKTICK = 328, - ASSIGN = 329, - SUB_ASSIGN = 330, - ADD_ASSIGN = 331, - MOD_ASSIGN = 332, - DIV_ASSIGN = 333, - MUL_ASSIGN = 334, - OR_OP = 335, - AND_OP = 336, - NCLOSE = 337, - NOPEN = 338, - LOWER_THAN_ELSE = 339, - ELSE = 340, - LOWER_THAN_DEREF = 341 - }; + enum yytokentype + { + KNOWN_ERROR_TOK = 258, + IDENTIFIER = 259, + CONSTANT = 260, + STRING = 261, + TYPE = 262, + NUMBER = 263, + ERROR = 264, + EOL = 265, + SIZEOF = 266, + D_TRUE = 267, + D_FALSE = 268, + PTR_OP = 269, + INC_OP = 270, + DEC_OP = 271, + LEFT_OP = 272, + RIGHT_OP = 273, + LEFT_ASSIGN = 274, + RIGHT_ASSIGN = 275, + AND_ASSIGN = 276, + XOR_ASSIGN = 277, + OR_ASSIGN = 278, + TYPE_NAME = 279, + TYPEDEF = 280, + EXTERN = 281, + STATIC = 282, + CHAR = 283, + SHORT = 284, + INT = 285, + LONG = 286, + SIGNED = 287, + UNSIGNED = 288, + FLOAT = 289, + DOUBLE = 290, + CONST = 291, + VOID = 292, + STRUCT = 293, + UNION = 294, + ENUM = 295, + ELLIPSIS = 296, + IF = 297, + LOCAL = 298, + PARAM = 299, + GLOBAL = 300, + FUNC = 301, + DYNINST = 302, + INST = 303, + REGISTER = 304, + NEWLINE = 305, + CASE = 306, + DEFAULT = 307, + SWITCH = 308, + RETURN = 309, + NILL = 310, + EOF_TOK = 311, + DOT = 312, + ASTERISK = 313, + AMPERSAND = 314, + COMMA = 315, + NOT = 316, + OR = 317, + AND = 318, + LESS_EQ = 319, + GREATER_EQ = 320, + EQ = 321, + NOT_EQ = 322, + COLON = 323, + SEMI = 324, + START_BLOCK = 325, + END_BLOCK = 326, + DOLLAR = 327, + BACKTICK = 328, + AND_OP = 329, + OR_OP = 330, + MUL_ASSIGN = 331, + DIV_ASSIGN = 332, + MOD_ASSIGN = 333, + ADD_ASSIGN = 334, + SUB_ASSIGN = 335, + ASSIGN = 336, + NOPEN = 337, + NCLOSE = 338, + LOWER_THAN_ELSE = 339, + ELSE = 340, + LOWER_THAN_DEREF = 341 + }; #endif - +/* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE + +union YYSTYPE { -/* Line 2058 of yacc.c */ -#line 66 "../src/C.y" +#line 71 "C.y" /* yacc.c:1909 */ int ival; long lval; @@ -168,42 +167,31 @@ typedef union YYSTYPE std::vector > *snippetStringListPair; std::pair *snippetStringPair; +#line 171 "dynC.tab.h" /* yacc.c:1909 */ +}; -/* Line 2058 of yacc.c */ -#line 174 "dynC.tab.h" -} YYSTYPE; +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif +/* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; -} YYLTYPE; -# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +}; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif + extern YYSTYPE dynClval; extern YYLTYPE dynClloc; -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int dynCparse (void *YYPARSE_PARAM); -#else -int dynCparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus int dynCparse (void); -#else -int dynCparse (); -#endif -#endif /* ! YYPARSE_PARAM */ #endif /* !YY_DYNC_DYNC_TAB_H_INCLUDED */ diff --git a/dynC_API/src/lex.dynC.C b/dynC_API/src/lex.dynC.C index 09bbd0c2a7..b91e72c065 100644 --- a/dynC_API/src/lex.dynC.C +++ b/dynC_API/src/lex.dynC.C @@ -1,5 +1,6 @@ +#line 2 "lex.dynC.C" -#line 3 "lex.dynC.c" +#line 4 "lex.dynC.C" #define YY_INT_ALIGNED short int @@ -26,8 +27,8 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 37 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 1 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -106,25 +107,13 @@ typedef unsigned int flex_uint32_t; #endif /* ! FLEXINT_H */ -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST +/* TODO: this is always defined, so inline it */ #define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) #else -#define yyconst +#define yynoreturn #endif /* Returned upon end-of-file. */ @@ -160,7 +149,15 @@ typedef unsigned int flex_uint32_t; /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. @@ -177,7 +174,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; typedef size_t yy_size_t; #endif -extern yy_size_t dynCleng; +extern int dynCleng; extern FILE *dynCin, *dynCout; @@ -194,11 +191,18 @@ extern FILE *dynCin, *dynCout; */ #define YY_LESS_LINENO(n) \ do { \ - yy_size_t yyl;\ + int yyl;\ for ( yyl = n; yyl < dynCleng; ++yyl )\ if ( dynCtext[yyl] == '\n' )\ --dynClineno;\ }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --dynClineno;\ + }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ @@ -228,12 +232,12 @@ struct yy_buffer_state /* Size of input buffer in bytes, not including room for EOB * characters. */ - yy_size_t yy_buf_size; + int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - yy_size_t yy_n_chars; + int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -284,7 +288,7 @@ struct yy_buffer_state /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ -static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general @@ -303,11 +307,11 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* yy_hold_char holds the character lost when dynCtext is formed. */ static char yy_hold_char; -static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ -yy_size_t dynCleng; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int dynCleng; /* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; +static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ @@ -332,7 +336,7 @@ static void dynC_init_buffer (YY_BUFFER_STATE b,FILE *file ); YY_BUFFER_STATE dynC_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE dynC_scan_string (yyconst char *yy_str ); -YY_BUFFER_STATE dynC_scan_bytes (yyconst char *bytes,yy_size_t len ); +YY_BUFFER_STATE dynC_scan_bytes (yyconst char *bytes,int len ); void *dynCalloc (yy_size_t ); void *dynCrealloc (void *,yy_size_t ); @@ -364,12 +368,12 @@ void dynCfree (void * ); /* Begin user sect3 */ -#define dynCwrap() 1 +#define dynCwrap() (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; -FILE *dynCin = (FILE *) 0, *dynCout = (FILE *) 0; +FILE *dynCin = NULL, *dynCout = NULL; typedef int yy_state_type; @@ -378,19 +382,22 @@ extern int dynClineno; int dynClineno = 1; extern char *dynCtext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif #define yytext_ptr dynCtext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); -static void yy_fatal_error (yyconst char msg[] ); +static void yynoreturn yy_fatal_error (yyconst char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up dynCtext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ - dynCleng = (size_t) (yy_cp - yy_bp); \ + dynCleng = (int) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; @@ -460,7 +467,7 @@ static yyconst flex_int16_t yy_accept[481] = 27, 33, 21, 14, 27, 33, 21, 30, 30, 0 } ; -static yyconst flex_int32_t yy_ec[256] = +static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, @@ -492,7 +499,7 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[66] = +static yyconst YY_CHAR yy_meta[66] = { 0, 1, 1, 2, 1, 3, 1, 1, 4, 1, 1, 5, 1, 1, 1, 1, 1, 6, 6, 6, 1, @@ -503,7 +510,7 @@ static yyconst flex_int32_t yy_meta[66] = 8, 7, 1, 7, 1 } ; -static yyconst flex_int16_t yy_base[494] = +static yyconst flex_uint16_t yy_base[494] = { 0, 0, 65, 128, 129, 130, 131, 1038, 1039, 1039, 1039, 1014, 1039, 114, 134, 1001, 1039, 1039, 1012, 130, 1039, @@ -621,7 +628,7 @@ static yyconst flex_int16_t yy_def[494] = } ; -static yyconst flex_int16_t yy_nxt[1105] = +static yyconst flex_uint16_t yy_nxt[1105] = { 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, @@ -897,10 +904,10 @@ int dynC_flex_debug = 0; #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *dynCtext; -#line 1 "../src/C.l" +#line 1 "C.l" -#line 15 "../src/C.l" +#line 17 "C.l" #include #include @@ -940,7 +947,7 @@ const bool lexVerbose = false; // set to true for debug mode //"$"{L}({L}|{D})* { yylval.sval = &dynCtext[1]; return(DYNINST_CALL); } -#line 944 "lex.dynC.c" +#line 951 "lex.dynC.C" #define INITIAL 0 #define comment 1 @@ -975,19 +982,19 @@ void dynCset_extra (YY_EXTRA_TYPE user_defined ); FILE *dynCget_in (void ); -void dynCset_in (FILE * in_str ); +void dynCset_in (FILE * _in_str ); FILE *dynCget_out (void ); -void dynCset_out (FILE * out_str ); +void dynCset_out (FILE * _out_str ); -yy_size_t dynCget_leng (void ); + int dynCget_leng (void ); char *dynCget_text (void ); int dynCget_lineno (void ); -void dynCset_lineno (int line_number ); +void dynCset_lineno (int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -1001,6 +1008,10 @@ extern int dynCwrap (void ); #endif #endif +#ifndef YY_NO_UNPUT + +#endif + #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif @@ -1021,7 +1032,12 @@ static int input (void ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -1029,7 +1045,7 @@ static int input (void ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO do { if (fwrite( dynCtext, dynCleng, 1, dynCout )) {} } while (0) +#define ECHO do { if (fwrite( dynCtext, (size_t) dynCleng, 1, dynCout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -1053,7 +1069,7 @@ static int input (void ); else \ { \ errno=0; \ - while ( (result = fread(buf, 1, max_size, dynCin))==0 && ferror(dynCin)) \ + while ( (result = (int) fread(buf, 1, max_size, dynCin))==0 && ferror(dynCin)) \ { \ if( errno != EINTR) \ { \ @@ -1108,7 +1124,7 @@ extern int dynClex (void); /* Code executed at the end of each rule. */ #ifndef YY_BREAK -#define YY_BREAK break; +#define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ @@ -1121,15 +1137,10 @@ extern int dynClex (void); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; -#line 56 "../src/C.l" - - -#line 1132 "lex.dynC.c" - if ( !(yy_init) ) { (yy_init) = 1; @@ -1156,7 +1167,13 @@ YY_DECL dynC_load_buffer_state( ); } - while ( 1 ) /* loops until end-of-file is reached */ + { +#line 58 "C.l" + + +#line 1175 "lex.dynC.C" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); @@ -1173,7 +1190,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -1185,7 +1202,7 @@ yy_match: if ( yy_current_state >= 481 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 1039 ); @@ -1224,225 +1241,225 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 60 "../src/C.l" +#line 62 "C.l" /* eat anything that's not a '*' */ YY_BREAK case 2: YY_RULE_SETUP -#line 61 "../src/C.l" +#line 63 "C.l" /* eat up '*'s not followed by '/'s */ YY_BREAK case 3: /* rule 3 can match eol */ YY_RULE_SETUP -#line 62 "../src/C.l" +#line 64 "C.l" ++line_num; YY_BREAK case 4: YY_RULE_SETUP -#line 63 "../src/C.l" +#line 65 "C.l" BEGIN(INITIAL); YY_BREAK case YY_STATE_EOF(comment): -#line 64 "../src/C.l" +#line 66 "C.l" {yylval.context = "Syntax Error: Unterminated block comment"; return(ERROR);} YY_BREAK case 5: YY_RULE_SETUP -#line 67 "../src/C.l" +#line 69 "C.l" { if(lexVerbose)printf("Inline Comment\n") /* inline comment */;} YY_BREAK case 6: YY_RULE_SETUP -#line 68 "../src/C.l" +#line 70 "C.l" { BEGIN(comment); } YY_BREAK case 7: YY_RULE_SETUP -#line 70 "../src/C.l" +#line 72 "C.l" { yylval.sval = strdup(dynCtext); return TYPE;} YY_BREAK case 8: YY_RULE_SETUP -#line 71 "../src/C.l" +#line 73 "C.l" {yylval.sval = strdup("char *"); return TYPE; } YY_BREAK case 9: YY_RULE_SETUP -#line 73 "../src/C.l" +#line 75 "C.l" {return STRUCT; } YY_BREAK case 10: YY_RULE_SETUP -#line 74 "../src/C.l" +#line 76 "C.l" {return UNION; } YY_BREAK case 11: YY_RULE_SETUP -#line 75 "../src/C.l" +#line 77 "C.l" {return ENUM; } YY_BREAK case 12: YY_RULE_SETUP -#line 77 "../src/C.l" +#line 79 "C.l" { return(CASE); } YY_BREAK case 13: YY_RULE_SETUP -#line 78 "../src/C.l" +#line 80 "C.l" { return(CONST); } YY_BREAK case 14: YY_RULE_SETUP -#line 79 "../src/C.l" +#line 81 "C.l" { return(DEFAULT); } YY_BREAK case 15: YY_RULE_SETUP -#line 80 "../src/C.l" +#line 82 "C.l" { return(ELSE); } YY_BREAK case 16: YY_RULE_SETUP -#line 81 "../src/C.l" +#line 83 "C.l" { return(IF); } YY_BREAK case 17: YY_RULE_SETUP -#line 82 "../src/C.l" +#line 84 "C.l" { return(RETURN); } YY_BREAK case 18: YY_RULE_SETUP -#line 83 "../src/C.l" +#line 85 "C.l" { return(SIZEOF); } YY_BREAK case 19: YY_RULE_SETUP -#line 84 "../src/C.l" +#line 86 "C.l" { return(STATIC); } YY_BREAK case 20: YY_RULE_SETUP -#line 85 "../src/C.l" +#line 87 "C.l" { return(SWITCH); } YY_BREAK case 21: YY_RULE_SETUP -#line 86 "../src/C.l" +#line 88 "C.l" { return(TYPEDEF); } YY_BREAK case 22: YY_RULE_SETUP -#line 87 "../src/C.l" +#line 89 "C.l" { return(D_TRUE); } YY_BREAK case 23: YY_RULE_SETUP -#line 88 "../src/C.l" +#line 90 "C.l" { return(D_FALSE); } YY_BREAK case 24: YY_RULE_SETUP -#line 90 "../src/C.l" +#line 92 "C.l" { return(LOCAL); } YY_BREAK case 25: YY_RULE_SETUP -#line 91 "../src/C.l" +#line 93 "C.l" { return(PARAM); } YY_BREAK case 26: YY_RULE_SETUP -#line 92 "../src/C.l" +#line 94 "C.l" { return(GLOBAL); } YY_BREAK case 27: YY_RULE_SETUP -#line 93 "../src/C.l" +#line 95 "C.l" { return(DYNINST); } YY_BREAK case 28: YY_RULE_SETUP -#line 94 "../src/C.l" +#line 96 "C.l" { return(INST); } YY_BREAK case 29: YY_RULE_SETUP -#line 95 "../src/C.l" +#line 97 "C.l" { return(FUNC); } YY_BREAK case 30: YY_RULE_SETUP -#line 96 "../src/C.l" +#line 98 "C.l" { return(FUNC); } YY_BREAK case 31: YY_RULE_SETUP -#line 97 "../src/C.l" +#line 99 "C.l" { return(REGISTER); } YY_BREAK case 32: YY_RULE_SETUP -#line 98 "../src/C.l" +#line 100 "C.l" {return (NILL); } YY_BREAK case 33: YY_RULE_SETUP -#line 100 "../src/C.l" +#line 102 "C.l" {yylval.sval = strdup(dynCtext); if(lexVerbose) printf("ID: %s\n", dynCtext); return(IDENTIFIER); } YY_BREAK case 34: YY_RULE_SETUP -#line 104 "../src/C.l" +#line 106 "C.l" { yylval.ival = atoi(dynCtext); return NUMBER;} YY_BREAK case 35: YY_RULE_SETUP -#line 106 "../src/C.l" +#line 108 "C.l" { return(CONSTANT); } YY_BREAK case 36: YY_RULE_SETUP -#line 107 "../src/C.l" +#line 109 "C.l" { return(CONSTANT); } YY_BREAK case 37: YY_RULE_SETUP -#line 108 "../src/C.l" +#line 110 "C.l" { return(CONSTANT); } YY_BREAK case 38: /* rule 38 can match eol */ YY_RULE_SETUP -#line 109 "../src/C.l" +#line 111 "C.l" { return(CONSTANT); } YY_BREAK case 39: YY_RULE_SETUP -#line 111 "../src/C.l" +#line 113 "C.l" { return(CONSTANT); } YY_BREAK case 40: YY_RULE_SETUP -#line 112 "../src/C.l" +#line 114 "C.l" { return(CONSTANT); } YY_BREAK case 41: YY_RULE_SETUP -#line 113 "../src/C.l" +#line 115 "C.l" { return(CONSTANT); } YY_BREAK case 42: YY_RULE_SETUP -#line 115 "../src/C.l" +#line 117 "C.l" {if(lexVerbose)printf("String Mode!\n"); c_string_buf = ""; BEGIN(stringmode);} YY_BREAK case 43: YY_RULE_SETUP -#line 119 "../src/C.l" +#line 121 "C.l" { /* saw closing quote - all done */ // this string handling code was taken from the flex manual if(lexVerbose)printf("string done\n"); @@ -1454,7 +1471,7 @@ YY_RULE_SETUP case 44: /* rule 44 can match eol */ YY_RULE_SETUP -#line 127 "../src/C.l" +#line 129 "C.l" { /* error - unterminated strin constant */ yylval.context = "Unterminated string constant"; yycolumn = 1; @@ -1464,7 +1481,7 @@ YY_RULE_SETUP YY_BREAK case 45: YY_RULE_SETUP -#line 134 "../src/C.l" +#line 136 "C.l" { /* octal escape sequence */ int result; (void) sscanf( dynCtext + 1, "%o", &result ); @@ -1480,7 +1497,7 @@ YY_RULE_SETUP YY_BREAK case 46: YY_RULE_SETUP -#line 147 "../src/C.l" +#line 149 "C.l" { /* generate error - bad escape sequence */ yylval.context = "bad escape sequence"; // yylval.line_number = line_num; @@ -1489,38 +1506,38 @@ YY_RULE_SETUP YY_BREAK case 47: YY_RULE_SETUP -#line 152 "../src/C.l" +#line 154 "C.l" c_string_buf += '\n'; YY_BREAK case 48: YY_RULE_SETUP -#line 153 "../src/C.l" +#line 155 "C.l" c_string_buf += '\t'; YY_BREAK case 49: YY_RULE_SETUP -#line 154 "../src/C.l" +#line 156 "C.l" c_string_buf += '\r'; YY_BREAK case 50: YY_RULE_SETUP -#line 155 "../src/C.l" +#line 157 "C.l" c_string_buf += '\b'; YY_BREAK case 51: YY_RULE_SETUP -#line 156 "../src/C.l" +#line 158 "C.l" c_string_buf += '\f'; YY_BREAK case 52: /* rule 52 can match eol */ YY_RULE_SETUP -#line 158 "../src/C.l" +#line 160 "C.l" c_string_buf += dynCtext[1]; YY_BREAK case 53: YY_RULE_SETUP -#line 159 "../src/C.l" +#line 161 "C.l" { char *yptr = dynCtext; while ( *yptr ) { c_string_buf += *yptr++; } @@ -1529,277 +1546,277 @@ YY_RULE_SETUP case 54: YY_RULE_SETUP -#line 166 "../src/C.l" +#line 168 "C.l" { return(ELLIPSIS); } YY_BREAK case 55: YY_RULE_SETUP -#line 167 "../src/C.l" +#line 169 "C.l" { return(RIGHT_ASSIGN); } YY_BREAK case 56: YY_RULE_SETUP -#line 168 "../src/C.l" +#line 170 "C.l" { return(LEFT_ASSIGN); } YY_BREAK case 57: YY_RULE_SETUP -#line 169 "../src/C.l" +#line 171 "C.l" { return(ADD_ASSIGN); } YY_BREAK case 58: YY_RULE_SETUP -#line 170 "../src/C.l" +#line 172 "C.l" { return(SUB_ASSIGN); } YY_BREAK case 59: YY_RULE_SETUP -#line 171 "../src/C.l" +#line 173 "C.l" { return(MUL_ASSIGN); } YY_BREAK case 60: YY_RULE_SETUP -#line 172 "../src/C.l" +#line 174 "C.l" { return(DIV_ASSIGN); } YY_BREAK case 61: YY_RULE_SETUP -#line 173 "../src/C.l" +#line 175 "C.l" { return(MOD_ASSIGN); } YY_BREAK case 62: YY_RULE_SETUP -#line 174 "../src/C.l" +#line 176 "C.l" { return(AND_ASSIGN); } YY_BREAK case 63: YY_RULE_SETUP -#line 175 "../src/C.l" +#line 177 "C.l" { return(XOR_ASSIGN); } YY_BREAK case 64: YY_RULE_SETUP -#line 176 "../src/C.l" +#line 178 "C.l" { return(OR_ASSIGN); } YY_BREAK case 65: YY_RULE_SETUP -#line 177 "../src/C.l" +#line 179 "C.l" { return(RIGHT_OP); } YY_BREAK case 66: YY_RULE_SETUP -#line 178 "../src/C.l" +#line 180 "C.l" { return(LEFT_OP); } YY_BREAK case 67: YY_RULE_SETUP -#line 179 "../src/C.l" +#line 181 "C.l" { return(INC_OP); } YY_BREAK case 68: YY_RULE_SETUP -#line 180 "../src/C.l" +#line 182 "C.l" { return(DEC_OP); } YY_BREAK case 69: YY_RULE_SETUP -#line 181 "../src/C.l" +#line 183 "C.l" { return(PTR_OP); } YY_BREAK case 70: YY_RULE_SETUP -#line 182 "../src/C.l" +#line 184 "C.l" { return(AND); } YY_BREAK case 71: YY_RULE_SETUP -#line 183 "../src/C.l" +#line 185 "C.l" { return(OR); } YY_BREAK case 72: YY_RULE_SETUP -#line 184 "../src/C.l" +#line 186 "C.l" { return(LESS_EQ); } YY_BREAK case 73: YY_RULE_SETUP -#line 185 "../src/C.l" +#line 187 "C.l" { return(GREATER_EQ); } YY_BREAK case 74: YY_RULE_SETUP -#line 186 "../src/C.l" +#line 188 "C.l" { return(EQ); } YY_BREAK case 75: YY_RULE_SETUP -#line 187 "../src/C.l" +#line 189 "C.l" { return(NOT_EQ); } YY_BREAK case 76: YY_RULE_SETUP -#line 188 "../src/C.l" +#line 190 "C.l" { return(SEMI); } YY_BREAK case 77: YY_RULE_SETUP -#line 189 "../src/C.l" +#line 191 "C.l" { return('{'); } YY_BREAK case 78: YY_RULE_SETUP -#line 190 "../src/C.l" +#line 192 "C.l" { return('}'); } YY_BREAK case 79: YY_RULE_SETUP -#line 191 "../src/C.l" +#line 193 "C.l" { return(NOPEN); } YY_BREAK case 80: YY_RULE_SETUP -#line 192 "../src/C.l" +#line 194 "C.l" { return(NCLOSE); } YY_BREAK case 81: YY_RULE_SETUP -#line 193 "../src/C.l" +#line 195 "C.l" { return(COMMA); } YY_BREAK case 82: YY_RULE_SETUP -#line 194 "../src/C.l" +#line 196 "C.l" { return(COLON); } YY_BREAK case 83: YY_RULE_SETUP -#line 195 "../src/C.l" +#line 197 "C.l" { return(ASSIGN); } YY_BREAK case 84: YY_RULE_SETUP -#line 196 "../src/C.l" +#line 198 "C.l" { if(lexVerbose)printf("(\n"); return('('); } YY_BREAK case 85: YY_RULE_SETUP -#line 197 "../src/C.l" +#line 199 "C.l" { if(lexVerbose)printf(")\n"); return(')'); } YY_BREAK case 86: YY_RULE_SETUP -#line 198 "../src/C.l" +#line 200 "C.l" { return('['); } YY_BREAK case 87: YY_RULE_SETUP -#line 199 "../src/C.l" +#line 201 "C.l" { return(']'); } YY_BREAK case 88: YY_RULE_SETUP -#line 200 "../src/C.l" +#line 202 "C.l" { return(DOT); } YY_BREAK case 89: YY_RULE_SETUP -#line 201 "../src/C.l" +#line 203 "C.l" { return('&'); } YY_BREAK case 90: YY_RULE_SETUP -#line 202 "../src/C.l" +#line 204 "C.l" { return('!'); } YY_BREAK case 91: YY_RULE_SETUP -#line 203 "../src/C.l" +#line 205 "C.l" { return('~'); } YY_BREAK case 92: YY_RULE_SETUP -#line 204 "../src/C.l" +#line 206 "C.l" { return('-'); } YY_BREAK case 93: YY_RULE_SETUP -#line 205 "../src/C.l" +#line 207 "C.l" { return('+'); } YY_BREAK case 94: YY_RULE_SETUP -#line 206 "../src/C.l" +#line 208 "C.l" { return('*'); } YY_BREAK case 95: YY_RULE_SETUP -#line 207 "../src/C.l" +#line 209 "C.l" { return('/'); } YY_BREAK case 96: YY_RULE_SETUP -#line 208 "../src/C.l" +#line 210 "C.l" { return('%'); } YY_BREAK case 97: YY_RULE_SETUP -#line 209 "../src/C.l" +#line 211 "C.l" { return('<'); } YY_BREAK case 98: YY_RULE_SETUP -#line 210 "../src/C.l" +#line 212 "C.l" { return('>'); } YY_BREAK case 99: YY_RULE_SETUP -#line 211 "../src/C.l" +#line 213 "C.l" { return('^'); } YY_BREAK case 100: YY_RULE_SETUP -#line 212 "../src/C.l" +#line 214 "C.l" { return('|'); } YY_BREAK case 101: YY_RULE_SETUP -#line 213 "../src/C.l" +#line 215 "C.l" { return('?'); } YY_BREAK case 102: YY_RULE_SETUP -#line 214 "../src/C.l" +#line 216 "C.l" { if(lexVerbose)printf("Backtick\n"); return(BACKTICK); } YY_BREAK case 103: YY_RULE_SETUP -#line 215 "../src/C.l" +#line 217 "C.l" { } YY_BREAK case 104: /* rule 104 can match eol */ YY_RULE_SETUP -#line 217 "../src/C.l" +#line 219 "C.l" {if(strstr(dynCtext, "//") != NULL){++line_num;}else{if(strncmp(dynCtext,"/*", 2) == 0){BEGIN(comment);++line_num;}else{if(lexVerbose)printf("No Semi!\n"); fatalError = true; dynClloc.first_column = yycolumn; yylval.context = "syntax error: missing ';'!"; yyless(dynCleng - 1); return(ERROR);}}} YY_BREAK case 105: /* rule 105 can match eol */ YY_RULE_SETUP -#line 219 "../src/C.l" +#line 221 "C.l" {if(lexVerbose)printf("New Line!\n"); line_num++; yycolumn = 0; lineStr = "";} YY_BREAK case 106: YY_RULE_SETUP -#line 221 "../src/C.l" +#line 223 "C.l" { if(lexVerbose) printf("Unrecognized [%s]\n", dynCtext); /* ignore bad characters */ } YY_BREAK case 107: YY_RULE_SETUP -#line 225 "../src/C.l" +#line 227 "C.l" ECHO; YY_BREAK -#line 1803 "lex.dynC.c" +#line 1820 "lex.dynC.C" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(stringmode): yyterminate(); @@ -1931,6 +1948,7 @@ case YY_STATE_EOF(stringmode): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ + } /* end of user's declarations */ } /* end of dynClex */ /* yy_get_next_buffer - try to read in a new buffer @@ -1942,9 +1960,9 @@ case YY_STATE_EOF(stringmode): */ static int yy_get_next_buffer (void) { - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = (yytext_ptr); - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + yy_size_t number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) @@ -1973,7 +1991,7 @@ static int yy_get_next_buffer (void) /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -1986,7 +2004,7 @@ static int yy_get_next_buffer (void) else { - yy_size_t num_to_read = + int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -2000,7 +2018,7 @@ static int yy_get_next_buffer (void) if ( b->yy_is_our_buffer ) { - yy_size_t new_size = b->yy_buf_size * 2; + int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -2013,7 +2031,7 @@ static int yy_get_next_buffer (void) } else /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; + b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( @@ -2055,9 +2073,9 @@ static int yy_get_next_buffer (void) else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) dynCrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); @@ -2076,15 +2094,15 @@ static int yy_get_next_buffer (void) static yy_state_type yy_get_previous_state (void) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -2096,7 +2114,7 @@ static int yy_get_next_buffer (void) if ( yy_current_state >= 481 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; } return yy_current_state; @@ -2109,10 +2127,10 @@ static int yy_get_next_buffer (void) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { - register int yy_is_jam; - register char *yy_cp = (yy_c_buf_p); + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -2124,12 +2142,16 @@ static int yy_get_next_buffer (void) if ( yy_current_state >= 481 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; yy_is_jam = (yy_current_state == 480); return yy_is_jam ? 0 : yy_current_state; } +#ifndef YY_NO_UNPUT + +#endif + #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) @@ -2154,7 +2176,7 @@ static int yy_get_next_buffer (void) else { /* need more input */ - yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) @@ -2178,7 +2200,7 @@ static int yy_get_next_buffer (void) case EOB_ACT_END_OF_FILE: { if ( dynCwrap( ) ) - return EOF; + return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; @@ -2285,7 +2307,7 @@ static void dynC_load_buffer_state (void) if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in dynC_create_buffer()" ); - b->yy_buf_size = size; + b->yy_buf_size = (yy_size_t)size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. @@ -2432,7 +2454,7 @@ void dynCpop_buffer_state (void) */ static void dynCensure_buffer_stack (void) { - yy_size_t num_to_alloc; + int num_to_alloc; if (!(yy_buffer_stack)) { @@ -2440,7 +2462,7 @@ static void dynCensure_buffer_stack (void) * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ - num_to_alloc = 1; + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)dynCalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); @@ -2457,7 +2479,7 @@ static void dynCensure_buffer_stack (void) if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; + yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)dynCrealloc @@ -2487,7 +2509,7 @@ YY_BUFFER_STATE dynC_scan_buffer (char * base, yy_size_t size ) base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ - return 0; + return NULL; b = (YY_BUFFER_STATE) dynCalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) @@ -2496,7 +2518,7 @@ YY_BUFFER_STATE dynC_scan_buffer (char * base, yy_size_t size ) b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; - b->yy_input_file = 0; + b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; @@ -2519,7 +2541,7 @@ YY_BUFFER_STATE dynC_scan_buffer (char * base, yy_size_t size ) YY_BUFFER_STATE dynC_scan_string (yyconst char * yystr ) { - return dynC_scan_bytes(yystr,strlen(yystr) ); + return dynC_scan_bytes(yystr,(int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to dynClex() will @@ -2529,7 +2551,7 @@ YY_BUFFER_STATE dynC_scan_string (yyconst char * yystr ) * * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE dynC_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) +YY_BUFFER_STATE dynC_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; @@ -2537,7 +2559,7 @@ YY_BUFFER_STATE dynC_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_le yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; + n = (yy_size_t) _yybytes_len + 2; buf = (char *) dynCalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in dynC_scan_bytes()" ); @@ -2563,9 +2585,9 @@ YY_BUFFER_STATE dynC_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_le #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg ) +static void yynoreturn yy_fatal_error (yyconst char* msg ) { - (void) fprintf( stderr, "%s\n", msg ); + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -2616,7 +2638,7 @@ FILE *dynCget_out (void) /** Get the length of the current token. * */ -yy_size_t dynCget_leng (void) +int dynCget_leng (void) { return dynCleng; } @@ -2631,29 +2653,29 @@ char *dynCget_text (void) } /** Set the current line number. - * @param line_number + * @param _line_number line number * */ -void dynCset_lineno (int line_number ) +void dynCset_lineno (int _line_number ) { - dynClineno = line_number; + dynClineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. - * @param in_str A readable stream. + * @param _in_str A readable stream. * * @see dynC_switch_to_buffer */ -void dynCset_in (FILE * in_str ) +void dynCset_in (FILE * _in_str ) { - dynCin = in_str ; + dynCin = _in_str ; } -void dynCset_out (FILE * out_str ) +void dynCset_out (FILE * _out_str ) { - dynCout = out_str ; + dynCout = _out_str ; } int dynCget_debug (void) @@ -2661,9 +2683,9 @@ int dynCget_debug (void) return dynC_flex_debug; } -void dynCset_debug (int bdebug ) +void dynCset_debug (int _bdebug ) { - dynC_flex_debug = bdebug ; + dynC_flex_debug = _bdebug ; } static int yy_init_globals (void) @@ -2675,10 +2697,10 @@ static int yy_init_globals (void) /* We do not touch dynClineno unless the option is enabled. */ dynClineno = 1; - (yy_buffer_stack) = 0; + (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; - (yy_c_buf_p) = (char *) 0; + (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; @@ -2687,8 +2709,8 @@ static int yy_init_globals (void) dynCin = stdin; dynCout = stdout; #else - dynCin = (FILE *) 0; - dynCout = (FILE *) 0; + dynCin = NULL; + dynCout = NULL; #endif /* For future reference: Set errno on error, since we are called by @@ -2726,7 +2748,8 @@ int dynClex_destroy (void) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { - register int i; + + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2735,7 +2758,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; @@ -2745,11 +2768,12 @@ static int yy_flex_strlen (yyconst char * s ) void *dynCalloc (yy_size_t size ) { - return (void *) malloc( size ); + return malloc(size); } void *dynCrealloc (void * ptr, yy_size_t size ) { + /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -2757,17 +2781,17 @@ void *dynCrealloc (void * ptr, yy_size_t size ) * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ - return (void *) realloc( (char *) ptr, size ); + return realloc(ptr, size); } void dynCfree (void * ptr ) { - free( (char *) ptr ); /* see dynCrealloc() for (char *) cast */ + free( (char *) ptr ); /* see dynCrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" -#line 225 "../src/C.l" +#line 227 "C.l" From f5c18e7bfe2f7db5c17bc44d09cdaaa30b026674 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Wed, 4 May 2016 23:22:16 -0400 Subject: [PATCH 029/180] Fix warnings --- common/src/util.C | 4 +- dataflowAPI/src/stackanalysis.C | 56 +++++++++---------- dwarf/h/dwarfHandle.h | 5 +- dwarf/src/dwarfHandle.C | 7 +-- dwarf/src/dwarfResult.C | 2 +- dynC_API/h/snippetGen.h | 6 +- dynC_API/src/dynC.C | 5 +- dyninstAPI/src/BPatch_addressSpace.C | 6 +- dyninstAPI/src/Relocation/Springboard.h | 5 +- .../src/Relocation/Widgets/StackModWidget.h | 2 +- dyninstAPI/src/StackMod/StackAccess.C | 6 +- dyninstAPI/src/StackMod/StackModChecker.C | 2 +- dyninstAPI/src/StackMod/StackModExpr.C | 6 +- dyninstAPI/src/StackMod/StackModExpr.h | 2 +- dyninstAPI/src/ast.C | 4 +- dyninstAPI/src/ast.h | 6 +- dyninstAPI/src/binaryEdit.C | 1 - dyninstAPI/src/inst-x86.C | 9 --- instructionAPI/src/BinaryFunction.C | 54 +++++++++--------- parseAPI/src/BoundFactCalculator.h | 4 +- parseAPI/src/IndirectAnalyzer.C | 2 +- parseAPI/src/JumpTablePred.C | 2 +- parseAPI/src/util.h | 2 +- parseThat/src/record.C | 8 +-- proccontrol/src/loadLibrary/codegen-linux.C | 1 - stackwalk/src/linux-x86-swk.C | 7 --- symtabAPI/h/Module.h | 2 +- symtabAPI/src/emitElfStatic-x86.C | 4 -- symtabAPI/src/emitElfStatic.h | 4 +- 29 files changed, 94 insertions(+), 130 deletions(-) diff --git a/common/src/util.C b/common/src/util.C index cb73474aa4..df47e181a3 100644 --- a/common/src/util.C +++ b/common/src/util.C @@ -44,9 +44,9 @@ COMMON_EXPORT unsigned addrHashCommon(const Address &addr) { // inspired by hashs of string class - register unsigned result = 5381; + unsigned result = 5381; - register Address accumulator = addr; + Address accumulator = addr; while (accumulator > 0) { // We use 3 bits at a time from the address result = (result << 4) + result + (accumulator & 0x07); diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 43285b259a..4cdce41fcd 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -1101,9 +1101,9 @@ void StackAnalysis::handleDiv(Instruction::Ptr insn, Expression::Ptr quotient = operands[1].getValue(); Expression::Ptr remainder = operands[0].getValue(); Expression::Ptr divisor = operands[2].getValue(); - assert(typeid(*quotient) == typeid(RegisterAST)); - assert(typeid(*remainder) == typeid(RegisterAST)); - assert(typeid(*divisor) != typeid(Immediate)); + assert(dynamic_cast(quotient.get())); + assert(dynamic_cast(remainder.get())); + assert(!dynamic_cast(divisor.get())); MachRegister quotientReg = (boost::dynamic_pointer_cast(quotient))->getID(); @@ -1131,7 +1131,7 @@ void StackAnalysis::handleMul(Instruction::Ptr insn, assert(operands.size() == 2 || operands.size() == 3); Expression::Ptr target = operands[0].getValue(); - assert(typeid(*target) == typeid(RegisterAST)); + assert(dynamic_cast(target.get())); MachRegister targetReg = (boost::dynamic_pointer_cast(target))->getID(); @@ -1143,16 +1143,16 @@ void StackAnalysis::handleMul(Instruction::Ptr insn, Expression::Ptr multiplicand = operands[1].getValue(); Expression::Ptr multiplier = operands[2].getValue(); - if (typeid(*multiplier) == typeid(Immediate)) { + if (dynamic_cast(multiplier.get())) { // Form 2 - assert(typeid(*multiplicand) == typeid(RegisterAST) || - typeid(*multiplicand) == typeid(Dereference)); + assert(dynamic_cast(multiplicand.get()) || + dynamic_cast(multiplicand.get())); long multiplierVal = multiplier->eval().convert(); if (multiplierVal == 0) { xferFuncs.push_back(TransferFunc::absFunc(Absloc(targetReg), 0)); retopBaseSubReg(targetReg, xferFuncs); } else if (multiplierVal == 1) { - if (typeid(*multiplicand) == typeid(RegisterAST)) { + if (dynamic_cast(multiplicand.get())) { // mul reg1, reg2, 1 MachRegister multiplicandReg = boost::dynamic_pointer_cast< RegisterAST>(multiplicand)->getID(); @@ -1173,9 +1173,9 @@ void StackAnalysis::handleMul(Instruction::Ptr insn, } } else { // Form 3 - assert(typeid(*multiplicand) == typeid(RegisterAST)); - assert(typeid(*multiplier) == typeid(RegisterAST) || - typeid(*multiplier) == typeid(Dereference)); + assert(dynamic_cast(multiplicand.get())); + assert(dynamic_cast(multiplier.get()) || + dynamic_cast(multiplier.get())); MachRegister multiplicandReg = boost::dynamic_pointer_cast< RegisterAST>(multiplicand)->getID(); xferFuncs.push_back(TransferFunc::retopFunc(Absloc(targetReg))); @@ -1385,7 +1385,7 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, } else { // Case 5a Expression::Ptr immExpr = operands[1].getValue(); - assert(typeid(*immExpr) == typeid(Immediate)); + assert(dynamic_cast(immExpr.get())); long immVal = immExpr->eval().convert(); xferFuncs.push_back(TransferFunc::deltaFunc(writtenLoc, sign * immVal)); @@ -1514,26 +1514,26 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, bool foundDelta = false; if (children.size() == 2) { - if (typeid(*children[0]) == typeid(Immediate)) { + if (dynamic_cast(children[0].get())) { // op1: imm + reg * imm deltaExpr = children[0]; Expression::Ptr scaleIndexExpr = children[1]; - assert(typeid(*scaleIndexExpr) == typeid(BinaryFunction)); + assert(dynamic_cast(scaleIndexExpr.get())); children.clear(); scaleIndexExpr->getChildren(children); regExpr = children[0]; scaleExpr = children[1]; - assert(typeid(*regExpr) == typeid(RegisterAST)); - assert(typeid(*scaleExpr) == typeid(Immediate)); + assert(dynamic_cast(regExpr.get())); + assert(dynamic_cast(scaleExpr.get())); foundScale = true; foundDelta = true; - } else if (typeid(*children[0]) == typeid(RegisterAST)) { + } else if (dynamic_cast(children[0].get())) { // op1: reg + imm regExpr = children[0]; deltaExpr = children[1]; - assert(typeid(*regExpr) == typeid(RegisterAST)); - assert(typeid(*deltaExpr) == typeid(Immediate)); + assert(dynamic_cast(regExpr.get())); + assert(dynamic_cast(deltaExpr.get())); foundDelta = true; } else { assert(false); @@ -1541,7 +1541,7 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, } else if (children.size() == 0) { // op1: reg regExpr = srcExpr; - assert(typeid(*regExpr) == typeid(RegisterAST)); + assert(dynamic_cast(regExpr.get())); } else { assert(false); } @@ -1576,12 +1576,12 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, bool foundDelta = false; assert(children.size() == 2); - if (typeid(*children[1]) == typeid(Immediate)) { + if (dynamic_cast(children[1].get())) { // op1: reg + reg * imm + imm // Extract the delta and continue on to get base, index, and scale deltaExpr = children[1]; Expression::Ptr sibExpr = children[0]; - assert(typeid(*sibExpr) == typeid(BinaryFunction)); + assert(dynamic_cast(sibExpr.get())); children.clear(); sibExpr->getChildren(children); assert(children.size() == 2); @@ -1591,7 +1591,7 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, // op1: reg + reg * imm baseExpr = children[0]; Expression::Ptr scaleIndexExpr = children[1]; - assert(typeid(*scaleIndexExpr) == typeid(BinaryFunction)); + assert(dynamic_cast(scaleIndexExpr.get())); // Extract the index and scale children.clear(); @@ -1600,9 +1600,9 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, indexExpr = children[0]; scaleExpr = children[1]; - assert(typeid(*baseExpr) == typeid(RegisterAST)); - assert(typeid(*indexExpr) == typeid(RegisterAST)); - assert(typeid(*scaleExpr) == typeid(Immediate)); + assert(dynamic_cast(baseExpr.get())); + assert(dynamic_cast(indexExpr.get())); + assert(dynamic_cast(scaleExpr.get())); MachRegister base = (boost::dynamic_pointer_cast(baseExpr))->getID(); @@ -1824,7 +1824,7 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, } else { // Case 5a Expression::Ptr immExpr = operands[1].getValue(); - assert(typeid(*immExpr) == typeid(Immediate)); + assert(dynamic_cast(immExpr.get())); long immVal = immExpr->eval().convert(); xferFuncs.push_back(TransferFunc::absFunc(writtenLoc, immVal)); } @@ -1904,7 +1904,7 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, } else { // Case 2 InstructionAPI::Expression::Ptr readExpr = operands[1].getValue(); - assert(typeid(*readExpr) == typeid(InstructionAPI::Immediate)); + assert(dynamic_cast(readExpr.get())); long readValue = readExpr->eval().convert(); xferFuncs.push_back(TransferFunc::absFunc(writtenLoc, readValue)); retopBaseSubReg(written, xferFuncs); diff --git a/dwarf/h/dwarfHandle.h b/dwarf/h/dwarfHandle.h index b03b308407..828c055d86 100644 --- a/dwarf/h/dwarfHandle.h +++ b/dwarf/h/dwarfHandle.h @@ -65,7 +65,6 @@ class DYNDWARF_EXPORT DwarfHandle { Elf_X *file; Elf_X *dbg_file; Dwarf_Handler err_func; - Dwarf_Ptr err_data; bool init_dbg(); void locate_dbg_file(); bool hasFrameData(Elf_X *elfx); @@ -75,12 +74,12 @@ class DYNDWARF_EXPORT DwarfHandle { static Dwarf_Handler defaultErrFunc; static void defaultDwarfError(Dwarf_Error err, Dwarf_Ptr arg); - DwarfHandle(std::string filename_, Elf_X *file_, Dwarf_Handler err_func_, Dwarf_Ptr err_data_); + DwarfHandle(std::string filename_, Elf_X *file_, Dwarf_Handler err_func_); public: ~DwarfHandle(); static DwarfHandle::ptr createDwarfHandle(std::string filename_, Elf_X *file_, - Dwarf_Handler err_func_ = defaultErrFunc, Dwarf_Ptr err_data_ = NULL); + Dwarf_Handler err_func_ = defaultErrFunc); Elf_X *origFile(); Elf_X *debugLinkFile(); diff --git a/dwarf/src/dwarfHandle.C b/dwarf/src/dwarfHandle.C index e3bf0eefb5..6c94f991a0 100644 --- a/dwarf/src/dwarfHandle.C +++ b/dwarf/src/dwarfHandle.C @@ -57,7 +57,7 @@ void DwarfHandle::defaultDwarfError(Dwarf_Error err, Dwarf_Ptr p) { Dwarf_Handler DwarfHandle::defaultErrFunc = DwarfHandle::defaultDwarfError; DwarfHandle::DwarfHandle(string filename_, Elf_X *file_, - Dwarf_Handler err_func_, Dwarf_Ptr err_data_) : + Dwarf_Handler err_func_) : init_dwarf_status(dwarf_status_uninitialized), dbg_file_data(NULL), file_data(NULL), @@ -67,7 +67,6 @@ DwarfHandle::DwarfHandle(string filename_, Elf_X *file_, file(file_), dbg_file(NULL), err_func(err_func_), - err_data(err_data_), filename(filename_) { @@ -239,7 +238,7 @@ DwarfHandle::~DwarfHandle() map DwarfHandle::all_dwarf_handles; DwarfHandle::ptr DwarfHandle::createDwarfHandle(string filename_, Elf_X *file_, - Dwarf_Handler err_func_, Dwarf_Ptr err_data_) + Dwarf_Handler err_func_) { map::iterator i; i = all_dwarf_handles.find(filename_); @@ -247,7 +246,7 @@ DwarfHandle::ptr DwarfHandle::createDwarfHandle(string filename_, Elf_X *file_, return i->second; } - DwarfHandle::ptr ret = DwarfHandle::ptr(new DwarfHandle(filename_, file_, err_func_, err_data_)); + DwarfHandle::ptr ret = DwarfHandle::ptr(new DwarfHandle(filename_, file_, err_func_)); all_dwarf_handles.insert(make_pair(filename_, ret)); return ret; } diff --git a/dwarf/src/dwarfResult.C b/dwarf/src/dwarfResult.C index b3124783a1..1231bb59cf 100644 --- a/dwarf/src/dwarfResult.C +++ b/dwarf/src/dwarfResult.C @@ -224,7 +224,7 @@ void ConcreteDwarfResult::pushOp(Operator op) { break; case Abs: CHECK_OPER(1); - v = ::abs((long) peek(0)); + v = std::abs((long) peek(0)); pop(0); push(v); break; diff --git a/dynC_API/h/snippetGen.h b/dynC_API/h/snippetGen.h index 63856a0ecc..d49932fa5a 100644 --- a/dynC_API/h/snippetGen.h +++ b/dynC_API/h/snippetGen.h @@ -70,8 +70,6 @@ class SnippetGenerator{ BPatch_addressSpace *addSpace; BPatch_image *image; - char *snippetName; - std::vector registers; public: @@ -81,13 +79,13 @@ class SnippetGenerator{ public: SnippetGenerator() : point(NULL), addSpace(NULL), image(NULL) {}; - SnippetGenerator(BPatch_point &pt, char *snName) : point(&pt), snippetName(snName) + SnippetGenerator(BPatch_point &pt) : point(&pt) { addSpace = point->getAddressSpace(); image = addSpace->getImage(); }; - SnippetGenerator(BPatch_addressSpace &aSpace, char *snName) : addSpace(&aSpace), snippetName(snName) + SnippetGenerator(BPatch_addressSpace &aSpace) : addSpace(&aSpace) { point = NULL; image = addSpace->getImage(); diff --git a/dynC_API/src/dynC.C b/dynC_API/src/dynC.C index bcb023bc43..25ccb26fe1 100644 --- a/dynC_API/src/dynC.C +++ b/dynC_API/src/dynC.C @@ -48,7 +48,6 @@ extern BPatch_point *snippetPoint; namespace dynC_API{ const std::string varNameBase = "dynC_mangled_"; - const bool debug = true; static int snippetCount = 0; std::map *createSnippet(const char *s, std::vector points){ @@ -80,7 +79,7 @@ namespace dynC_API{ printf("%s", s); set_lex_input(mutS); snippetPoint = (*it); - snippetGen = new SnippetGenerator(**it, mutName); + snippetGen = new SnippetGenerator(**it); if(dynCparse() == 0){ printf("parse_result is %s\n", (parse_result == NULL ? "null" : "not null")); @@ -125,7 +124,7 @@ namespace dynC_API{ char *mutName = strdup(name.c_str()); dynCSnippetName = mutName; snippetPoint = NULL; - snippetGen = new SnippetGenerator(addSpace, mutName); + snippetGen = new SnippetGenerator(addSpace); if(dynCparse() == 0){ free(mutS); free(mutName); diff --git a/dyninstAPI/src/BPatch_addressSpace.C b/dyninstAPI/src/BPatch_addressSpace.C index d2697246ed..37a0e59c2b 100644 --- a/dyninstAPI/src/BPatch_addressSpace.C +++ b/dyninstAPI/src/BPatch_addressSpace.C @@ -96,10 +96,8 @@ BPatch_function *BPatch_addressSpace::findOrCreateBPFunc(Dyninst::PatchAPI::Patc // check to see if the func_instance refers to a different // module, and that module contains a bpatch_func - BPatch_module* containing; - if (fi->mod() != NULL) { - containing = getImage()->findModule(fi->mod()->fileName().c_str()); - } + assert(fi->mod() != NULL); + BPatch_module* containing = getImage()->findModule(fi->mod()->fileName().c_str()); // findModule has a tendency to make new function objects... so // check the map again diff --git a/dyninstAPI/src/Relocation/Springboard.h b/dyninstAPI/src/Relocation/Springboard.h index 6c0acd95c4..442e27270d 100644 --- a/dyninstAPI/src/Relocation/Springboard.h +++ b/dyninstAPI/src/Relocation/Springboard.h @@ -208,9 +208,7 @@ class InstalledSpringboards typedef boost::shared_ptr Ptr; static const int Allocated; static const int UnallocatedStart; - InstalledSpringboards() : nextFuncID_(UnallocatedStart) - { - } + InstalledSpringboards() {} @@ -230,7 +228,6 @@ class InstalledSpringboards private: - int nextFuncID_; // tracks relocation addresses that need trap-based springboards std::set
relocTraps_; diff --git a/dyninstAPI/src/Relocation/Widgets/StackModWidget.h b/dyninstAPI/src/Relocation/Widgets/StackModWidget.h index 4493d8da27..0571242552 100644 --- a/dyninstAPI/src/Relocation/Widgets/StackModWidget.h +++ b/dyninstAPI/src/Relocation/Widgets/StackModWidget.h @@ -29,7 +29,7 @@ */ #ifndef _STACKMODWIDGET_H_ -#define _STACKMODWIDGE_H_ +#define _STACKMODWIDGET_H_ #include "Widget.h" class block_instance; diff --git a/dyninstAPI/src/StackMod/StackAccess.C b/dyninstAPI/src/StackMod/StackAccess.C index 297eb1d339..c05468cf16 100644 --- a/dyninstAPI/src/StackMod/StackAccess.C +++ b/dyninstAPI/src/StackMod/StackAccess.C @@ -510,19 +510,19 @@ bool getMemoryOffset(ParseAPI::Function* func, if (!val) break; // Won't find an offset for an immediate - if (typeid(*val) == typeid(InstructionAPI::Immediate)) { + if (dynamic_cast(val.get())) { continue; } // Won't find an offset for a registerAST. However, we do want to // record a push (e.g., callee-saved registers). - if (typeid(*val) == typeid(InstructionAPI::RegisterAST) && + if (dynamic_cast(val.get()) && insn->getOperation().getID() != e_push) { continue; } // If we have a dereference, extract the child - if (typeid(*val) == typeid(InstructionAPI::Dereference)) { + if (dynamic_cast(val.get())) { vector children; val->getChildren(children); if (children.size() == 1) { diff --git a/dyninstAPI/src/StackMod/StackModChecker.C b/dyninstAPI/src/StackMod/StackModChecker.C index f92357979c..c57ab49188 100644 --- a/dyninstAPI/src/StackMod/StackModChecker.C +++ b/dyninstAPI/src/StackMod/StackModChecker.C @@ -336,7 +336,7 @@ bool StackModChecker::addModsInternal(std::set mods) for (auto iter = points->begin(); iter != points->end(); ++iter) { BPatch_point* point = *iter; Address addr = (Address)(point->getAddress()); - BPatch_snippet* snip = new BPatch_stackInsertExpr(insert->size(), dispFromRSP); + BPatch_snippet* snip = new BPatch_stackInsertExpr(insert->size()); stackmods_printf("\t Generating INSERT of size %d at 0x%lx\n", insert->size(), addr); BPatchSnippetHandle* handle = bfunc->getAddSpace()->insertSnippet(*snip, *point, BPatch_callBefore, BPatch_lastSnippet); if (!handle) { diff --git a/dyninstAPI/src/StackMod/StackModExpr.C b/dyninstAPI/src/StackMod/StackModExpr.C index 0665e8396b..8b1a73532b 100644 --- a/dyninstAPI/src/StackMod/StackModExpr.C +++ b/dyninstAPI/src/StackMod/StackModExpr.C @@ -36,9 +36,9 @@ using namespace Dyninst; -BPatch_stackInsertExpr::BPatch_stackInsertExpr(int size, int dispFromRSP) +BPatch_stackInsertExpr::BPatch_stackInsertExpr(int size) { - ast_wrapper = AstNodePtr(AstNode::stackInsertNode(size, dispFromRSP, AstNode::GENERIC_AST)); + ast_wrapper = AstNodePtr(AstNode::stackInsertNode(size, AstNode::GENERIC_AST)); assert(BPatch::bpatch != NULL); } @@ -56,7 +56,7 @@ BPatch_stackMoveExpr::BPatch_stackMoveExpr() BPatch_canaryExpr::BPatch_canaryExpr() { - ast_wrapper = AstNodePtr(AstNode::stackInsertNode(0, 0, AstNode::CANARY_AST)); + ast_wrapper = AstNodePtr(AstNode::stackInsertNode(0, AstNode::CANARY_AST)); assert(BPatch::bpatch != NULL); } diff --git a/dyninstAPI/src/StackMod/StackModExpr.h b/dyninstAPI/src/StackMod/StackModExpr.h index b45556c60d..38cc235e8b 100644 --- a/dyninstAPI/src/StackMod/StackModExpr.h +++ b/dyninstAPI/src/StackMod/StackModExpr.h @@ -38,7 +38,7 @@ class BPatch_function; class BPatch_stackInsertExpr : public BPatch_snippet { public: // Creates a stack shift (insertion) of size - BPatch_stackInsertExpr(int size, int dispFromRSP = 0); + BPatch_stackInsertExpr(int size); }; class BPatch_stackRemoveExpr : public BPatch_snippet { diff --git a/dyninstAPI/src/ast.C b/dyninstAPI/src/ast.C index dea4666c41..bffbad88ce 100644 --- a/dyninstAPI/src/ast.C +++ b/dyninstAPI/src/ast.C @@ -163,8 +163,8 @@ AstNodePtr AstNode::nullNode() { return AstNodePtr(new AstNullNode()); } -AstNodePtr AstNode::stackInsertNode(int size, long dispFromRSP, MSpecialType type) { - return AstNodePtr(new AstStackInsertNode(size, dispFromRSP, type)); +AstNodePtr AstNode::stackInsertNode(int size, MSpecialType type) { + return AstNodePtr(new AstStackInsertNode(size, type)); } AstNodePtr AstNode::stackRemoveNode(int size, MSpecialType type) { diff --git a/dyninstAPI/src/ast.h b/dyninstAPI/src/ast.h index a5ce387822..b2bdf96d57 100644 --- a/dyninstAPI/src/ast.h +++ b/dyninstAPI/src/ast.h @@ -207,7 +207,7 @@ class AstNode : public Dyninst::PatchAPI::Snippet { // Factory methods.... static AstNodePtr nullNode(); - static AstNodePtr stackInsertNode(int size, long dispFromRSP = 0, MSpecialType type = GENERIC_AST); + static AstNodePtr stackInsertNode(int size, MSpecialType type = GENERIC_AST); static AstNodePtr stackRemoveNode(int size, MSpecialType type); static AstNodePtr stackRemoveNode(int size, MSpecialType type, func_instance* func, bool canaryAfterPrologue, long canaryHeight); static AstNodePtr stackGenericNode(); @@ -445,9 +445,8 @@ class AstNullNode : public AstNode { /* Stack Frame Modification */ class AstStackInsertNode : public AstNode { public: - AstStackInsertNode(int s, long d, MSpecialType t) : AstNode(), + AstStackInsertNode(int s, MSpecialType t) : AstNode(), size(s), - dispFromRSP(d), type(t) {}; virtual std::string format(std::string indent); @@ -463,7 +462,6 @@ class AstStackInsertNode : public AstNode { Register &retReg); int size; - long dispFromRSP; MSpecialType type; }; diff --git a/dyninstAPI/src/binaryEdit.C b/dyninstAPI/src/binaryEdit.C index 8b16ef6328..3ed0fcff5c 100644 --- a/dyninstAPI/src/binaryEdit.C +++ b/dyninstAPI/src/binaryEdit.C @@ -162,7 +162,6 @@ bool BinaryEdit::writeDataWord(void *inOther, const Address ADDRESS_LO = (Address)0; const Address ADDRESS_HI = (Address)(~(Address)0); -const unsigned HEAP_STAT_BUF_SIZE = (0x100000); Address BinaryEdit::inferiorMalloc(unsigned size, inferiorHeapType /*ignored*/, diff --git a/dyninstAPI/src/inst-x86.C b/dyninstAPI/src/inst-x86.C index fcaf3bc8e1..19c19322ef 100644 --- a/dyninstAPI/src/inst-x86.C +++ b/dyninstAPI/src/inst-x86.C @@ -1258,15 +1258,6 @@ unsigned char jccOpcodeFromRelOp(unsigned op) return 0x0; } -static inline void emitEnter(short imm16, codeGen &gen) { - GET_PTR(insn, gen); - *insn++ = 0xC8; - *((short*)insn) = imm16; - insn += sizeof(short); - *insn++ = 0; - SET_PTR(insn, gen); -} - Register emitFuncCall(opCode, codeGen &, pdvector &, bool, Address) { assert(0); return 0; diff --git a/instructionAPI/src/BinaryFunction.C b/instructionAPI/src/BinaryFunction.C index 3735e4bc3b..18c7762172 100644 --- a/instructionAPI/src/BinaryFunction.C +++ b/instructionAPI/src/BinaryFunction.C @@ -413,44 +413,44 @@ namespace Dyninst bool BinaryFunction::isAdd() const { - return typeid(*m_funcPtr) == typeid(addResult); + return dynamic_cast(m_funcPtr.get()) != nullptr; } bool BinaryFunction::isMultiply() const { - return typeid(*m_funcPtr) == typeid(multResult); + return dynamic_cast(m_funcPtr.get()) != nullptr; } bool BinaryFunction::isLeftShift() const { - return typeid(*m_funcPtr) == typeid(leftShiftResult); - } + return dynamic_cast(m_funcPtr.get()) != nullptr; + } - bool BinaryFunction::isRightArithmeticShift() const + bool BinaryFunction::isRightArithmeticShift() const { - return typeid(*m_funcPtr) == typeid(rightArithmeticShiftResult); - } - - bool BinaryFunction::isAndResult() const - { - return typeid(*m_funcPtr) == typeid(andResult); - } - - bool BinaryFunction::isOrResult() const - { - return typeid(*m_funcPtr) == typeid(orResult); - } - - bool BinaryFunction::isRightLogicalShift() const - { - return typeid(*m_funcPtr) == typeid(rightLogicalShiftResult); - } - - bool BinaryFunction::isRightRotate() const - { - return typeid(*m_funcPtr) == typeid(rightRotateResult); - } + return dynamic_cast(m_funcPtr.get()) != nullptr; + } + + bool BinaryFunction::isAndResult() const + { + return dynamic_cast(m_funcPtr.get()) != nullptr; + } + + bool BinaryFunction::isOrResult() const + { + return dynamic_cast(m_funcPtr.get()) != nullptr; + } + + bool BinaryFunction::isRightLogicalShift() const + { + return dynamic_cast(m_funcPtr.get()) != nullptr; + } + + bool BinaryFunction::isRightRotate() const + { + return dynamic_cast(m_funcPtr.get()) != nullptr; + } }; }; diff --git a/parseAPI/src/BoundFactCalculator.h b/parseAPI/src/BoundFactCalculator.h index 76867d8914..6a139bba11 100644 --- a/parseAPI/src/BoundFactCalculator.h +++ b/parseAPI/src/BoundFactCalculator.h @@ -25,7 +25,6 @@ class BoundFactsCalculator { bool firstBlock; ReachFact &rf; ThunkData &thunks; - Address jumpAddr; bool handleOneByteRead; std::unordered_map &expandCache; @@ -52,10 +51,9 @@ class BoundFactsCalculator { bool first, ReachFact &r, ThunkData &t, - Address addr, bool oneByteRead, std::unordered_map& cache): - func(f), slice(s), firstBlock(first), rf(r), thunks(t), jumpAddr(addr), handleOneByteRead(oneByteRead), expandCache(cache) {} + func(f), slice(s), firstBlock(first), rf(r), thunks(t), handleOneByteRead(oneByteRead), expandCache(cache) {} BoundFact *GetBoundFactIn(Node::Ptr node); BoundFact *GetBoundFactOut(Node::Ptr node); diff --git a/parseAPI/src/IndirectAnalyzer.C b/parseAPI/src/IndirectAnalyzer.C index 6c1a79789e..0a76aee456 100644 --- a/parseAPI/src/IndirectAnalyzer.C +++ b/parseAPI/src/IndirectAnalyzer.C @@ -49,7 +49,7 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vectorentry() == block, rf, thunks, block->last(), true, jtp.expandCache); + BoundFactsCalculator bfc(func, g, func->entry() == block, rf, thunks, true, jtp.expandCache); bfc.CalculateBoundedFacts(); BoundValue target; diff --git a/parseAPI/src/JumpTablePred.C b/parseAPI/src/JumpTablePred.C index 6c07eff1bd..6b028a645c 100644 --- a/parseAPI/src/JumpTablePred.C +++ b/parseAPI/src/JumpTablePred.C @@ -229,7 +229,7 @@ bool JumpTablePred::addNodeCallback(AssignmentPtr ap, set &visi // We create the CFG based on the found nodes GraphPtr g = BuildAnalysisGraph(visitedEdges); - BoundFactsCalculator bfc(func, g, func->entry() == block, rf, thunks, block->last(), false, expandCache); + BoundFactsCalculator bfc(func, g, func->entry() == block, rf, thunks, false, expandCache); bfc.CalculateBoundedFacts(); BoundValue target; diff --git a/parseAPI/src/util.h b/parseAPI/src/util.h index 01d20289fa..4703322c53 100644 --- a/parseAPI/src/util.h +++ b/parseAPI/src/util.h @@ -28,7 +28,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _UTIL_H_ -#define _HTIL_H_ +#define _UTIL_H_ #define HASHDEF(h,k) (h.find(k) != h.end()) diff --git a/parseThat/src/record.C b/parseThat/src/record.C index 3376ebc25a..278cc10bdf 100644 --- a/parseThat/src/record.C +++ b/parseThat/src/record.C @@ -266,7 +266,7 @@ bool record_search(record_t *newRecord) char raw_filename[ PATH_MAX ]; strncpy(raw_filename, newRecord->filename, sizeof(raw_filename)); - strncat(raw_filename, ".raw", sizeof(raw_filename) - strlen(raw_filename)); + strncat(raw_filename, ".raw", sizeof(raw_filename) - strlen(raw_filename) - 1); newRecord->raw_fd = fopen(raw_filename, "a"); fprintf(newRecord->raw_fd, "Raw transcript log start: %s\n", timestr); @@ -283,8 +283,8 @@ void record_update(record_t *newRecord) char new_index_filename[PATH_MAX]; strncpy(index_filename, config.record_dir, sizeof(index_filename)); - strncat(index_filename, "/", sizeof(index_filename) - strlen(index_filename)); - strncat(index_filename, HISTORY_RECORD_INDEX_FILE, sizeof(index_filename) - strlen(index_filename)); + strncat(index_filename, "/", sizeof(index_filename) - strlen(index_filename) - 1); + strncat(index_filename, HISTORY_RECORD_INDEX_FILE, sizeof(index_filename) - strlen(index_filename) - 1); errno = 0; index_fd = fopen(index_filename, "r"); if (!index_fd) { @@ -293,7 +293,7 @@ void record_update(record_t *newRecord) } strncpy(new_index_filename, index_filename, sizeof(new_index_filename)); - strncat(new_index_filename, ".update", sizeof(new_index_filename) - strlen(new_index_filename)); + strncat(new_index_filename, ".update", sizeof(new_index_filename) - strlen(new_index_filename) - 1); new_fd = fopen(new_index_filename, "w"); if (!new_fd) { fprintf(stderr, "Could not open %s\n", new_index_filename); diff --git a/proccontrol/src/loadLibrary/codegen-linux.C b/proccontrol/src/loadLibrary/codegen-linux.C index c891a7c971..c2017a36e2 100644 --- a/proccontrol/src/loadLibrary/codegen-linux.C +++ b/proccontrol/src/loadLibrary/codegen-linux.C @@ -22,7 +22,6 @@ static const int DLOPEN_MODE = RTLD_NOW | RTLD_GLOBAL; static const char DL_OPEN_FUNC_EXPORTED[] = "dlopen"; static const char DL_OPEN_LIBC_FUNC_EXPORTED[] = "__libc_dlopen_mode"; static const char DL_OPEN_FUNC_NAME[] = "do_dlopen"; -static const char DL_OPEN_FUNC_INTERNAL[] = "_dl_open"; bool Codegen::generateInt() { diff --git a/stackwalk/src/linux-x86-swk.C b/stackwalk/src/linux-x86-swk.C index 8b7cbb4e65..31ad2e1cf2 100644 --- a/stackwalk/src/linux-x86-swk.C +++ b/stackwalk/src/linux-x86-swk.C @@ -53,13 +53,6 @@ using namespace Dyninst; using namespace Dyninst::Stackwalker; -static const int fp_offset_32 = 28; -static const int pc_offset_32 = 60; -static const int frame_size_32 = 736; -static const int fp_offset_64 = 120; -static const int pc_offset_64 = 168; -static const int frame_size_64 = 1088; - struct sigframe_offsets { int fp_offset; int pc_offset; diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 33d299747b..2db2ac8144 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -73,7 +73,7 @@ class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable unsigned int second; unsigned int column; - Statement() : first(NULL), second(line_) {} + Statement() : first(NULL), second(0) {} struct StatementLess { bool operator () ( const Statement &lhs, const Statement &rhs ) const; }; diff --git a/symtabAPI/src/emitElfStatic-x86.C b/symtabAPI/src/emitElfStatic-x86.C index 2be086972c..9c4b6123f2 100644 --- a/symtabAPI/src/emitElfStatic-x86.C +++ b/symtabAPI/src/emitElfStatic-x86.C @@ -574,10 +574,6 @@ void emitElfStatic::buildGOT(Symtab *, LinkMap &lmap) { * instead of 4. So the header and trailler are the same, but extended to * 8 bytes. */ -static const Elf64_Word X86_HEADER = 0xffffffff; -static const Elf64_Word X86_TRAILER = 0x00000000; -static const Elf64_Xword X86_64_HEADER = 0xffffffffffffffffULL; -static const Elf64_Xword X86_64_TRAILER = 0x0000000000000000ULL; static const string DTOR_NAME(".dtors"); static const string CTOR_NAME(".ctors"); static const string DTOR_NAME2(".fini_array"); diff --git a/symtabAPI/src/emitElfStatic.h b/symtabAPI/src/emitElfStatic.h index 57a4a98587..708abf76b5 100644 --- a/symtabAPI/src/emitElfStatic.h +++ b/symtabAPI/src/emitElfStatic.h @@ -28,8 +28,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#if !defined(_emit_Elf_Static_h_) -#define _emit_Elf_Static_h +#ifndef _emit_Elf_Static_h_ +#define _emit_Elf_Static_h_ #include "Symtab.h" #include "Archive.h" From efe5e01d77b2710554fc3a488fe72c8ec90c25a0 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 13 May 2016 18:15:43 -0400 Subject: [PATCH 030/180] warnings --- dataflowAPI/src/SymEvalPolicy.C | 1 + dyninstAPI/src/Relocation/Widgets/CFWidget.C | 2 +- symtabAPI/src/Symtab-lookup.C | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dataflowAPI/src/SymEvalPolicy.C b/dataflowAPI/src/SymEvalPolicy.C index 5235246654..9eea90b2aa 100644 --- a/dataflowAPI/src/SymEvalPolicy.C +++ b/dataflowAPI/src/SymEvalPolicy.C @@ -350,6 +350,7 @@ Absloc SymEvalPolicy_64::convert(PowerpcRegisterClass regtype, int regNum) case powerpc_regclass_sr:break; case powerpc_last_register_class:break; } + assert(0); } Absloc SymEvalPolicy_64::convert(X86GeneralPurposeRegister r) diff --git a/dyninstAPI/src/Relocation/Widgets/CFWidget.C b/dyninstAPI/src/Relocation/Widgets/CFWidget.C index d0b39c88fa..c17cc829b4 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/CFWidget.C @@ -115,7 +115,7 @@ CFWidget::CFWidget(InstructionAPI::Instruction::Ptr insn, Address addr) : // I'm working around it here and in Movement-adhoc.C by checking _both_ // 32- and 64-bit. - Architecture fixme = insn_->getArch(); + //Architecture fixme = insn_->getArch(); //if (fixme == Arch_ppc32) fixme = Arch_ppc64; Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn_->getArch()))); diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 77785efb8f..0d014d960b 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -391,7 +391,7 @@ bool Symtab::findModuleByOffset(Module *&ret, Offset off) { std::sort(_mods.begin(), _mods.end(), module_less); // this should be a hash, really - for(int i = 0; i < _mods.size(); i++) + for(size_t i = 0; i < _mods.size(); i++) { // cout << *(_mods[i]) << endl; if(_mods[i]->addr() == off) From e10d05ff356554f110e9e63b3c848615f374ca78 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Wed, 25 May 2016 13:33:32 -0400 Subject: [PATCH 031/180] fix warnings --- instructionAPI/src/InstructionDecoder-aarch64.C | 4 ++-- instructionAPI/src/InstructionDecoder-aarch64.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/instructionAPI/src/InstructionDecoder-aarch64.C b/instructionAPI/src/InstructionDecoder-aarch64.C index 5166a4ec7a..a8e5e97e75 100644 --- a/instructionAPI/src/InstructionDecoder-aarch64.C +++ b/instructionAPI/src/InstructionDecoder-aarch64.C @@ -143,8 +143,8 @@ namespace Dyninst { is64Bit(true), isValid(true), insn(0), insn_in_progress(NULL), hasHw(false), hasShift(false), hasOption(false), hasN(false), immr(0), immrLen(0), sField(0), nField(0), nLen(0), - immlo(0), immloLen(0), _szField(-1), _Q(1), size(-1), - cmode(0), op(0), simdAlphabetImm(0) { + immlo(0), immloLen(0), _szField(-1), size(-1), + cmode(0), op(0), simdAlphabetImm(0), _Q(1) { aarch64_insn_entry::buildInsnTable(); aarch64_mask_entry::buildDecoderTable(); InstructionDecoder_aarch64::buildSysRegMap(); diff --git a/instructionAPI/src/InstructionDecoder-aarch64.h b/instructionAPI/src/InstructionDecoder-aarch64.h index 6f0e913606..e4320dc65a 100644 --- a/instructionAPI/src/InstructionDecoder-aarch64.h +++ b/instructionAPI/src/InstructionDecoder-aarch64.h @@ -148,8 +148,8 @@ namespace Dyninst { bool isPstateRead, isPstateWritten; bool isFPInsn, isSIMDInsn; - bool is64Bit; bool skipRn, skipRm; + bool is64Bit; bool isValid; void mainDecode(); From f88935f8f83a66dcc6d4afa6649c78135e1db387 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 30 Jun 2016 11:11:57 -0400 Subject: [PATCH 032/180] remove dead code --- dyninstAPI_RT/src/RTheap.c | 148 ------------------------------------- 1 file changed, 148 deletions(-) diff --git a/dyninstAPI_RT/src/RTheap.c b/dyninstAPI_RT/src/RTheap.c index eae69700d3..ecb68eeebb 100644 --- a/dyninstAPI_RT/src/RTheap.c +++ b/dyninstAPI_RT/src/RTheap.c @@ -76,49 +76,12 @@ static heapList_t *Heaps = NULL; static int psize = -1; -/* -static void heap_printMappings(int nmaps, dyninstmm_t *maps) -{ - int i; - fprintf(stderr, "memory mappings:\n"); - for(i = 0; i < nmaps; i++) { - dyninstmm_t *map = &maps[i]; - Address addr = (Address)map->pr_vaddr; - fprintf(stderr, " heap %2i: 0x%016lx-0x%016lx (%3lu pages, %.2fkB)\n", - i, addr, addr + map->pr_size - 1, - map->pr_size / psize, map->pr_size / 1024.0); - } -} -*/ - -static void heap_checkMappings(int nmaps, dyninstmm_t *maps) -{ - int i; - for (i = 0; i < nmaps-1; i++) { - if (maps[i].pr_vaddr + maps[i].pr_size > maps[i+1].pr_vaddr) { - fprintf(stderr, "*** memory mappings overlap\n"); - abort(); - } - } -} - static Address heap_alignUp(Address addr, int align) { if (addr % align == 0) return addr; return ((addr / align) + 1) * align; } -/* -static Address heap_alignDown(Address addr, int align) -{ - if (addr % align == 0) return addr; - return ((addr / align) + 0) * align; -} -*/ - -#define BEG(x) ((Address)(x)->pr_vaddr) -#define END(x) ((Address)(x)->pr_vaddr + (x)->pr_size) - static Address trymmap(size_t len, Address beg, Address end, size_t inc, int fd) { Address addr; @@ -134,117 +97,6 @@ static Address trymmap(size_t len, Address beg, Address end, size_t inc, int fd) return (Address) NULL; } -/* Attempt to mmap a region of memory of size LEN bytes somewhere - between LO and HI. Returns the address of the region on success, 0 - otherwise. MAPS is the current address space map, with NMAPS - elements. FD is the mmap file descriptor argument. */ -static Address constrained_mmap(size_t len, Address lo, Address hi, - const dyninstmm_t *maps, int nmaps, int fd) -{ - const dyninstmm_t *mlo, *mhi, *p; - Address beg, end, try; -#if defined (os_linux) && defined(arch_power) -// DYNINSTheap_loAddr should already be defined in DYNINSTos_malloc. -// Redefining here, just in case constrained_mmap is called from a different call path. - DYNINSTheap_loAddr = getpagesize(); -#endif - - if (lo > DYNINSTheap_hiAddr) return 0; - - if (lo < DYNINSTheap_loAddr) lo = DYNINSTheap_loAddr; - if (hi > DYNINSTheap_hiAddr) hi = DYNINSTheap_hiAddr; - - /* Round down to nearest page boundary */ - lo = lo & ~(psize-1); - hi = hi & ~(psize-1); - - /* Round up to nearest page boundary */ - if (len % psize) { - len += psize; - len = len & ~(psize-1); - } - - assert(lo < hi); - /* Find lowest (mlo) and highest (mhi) segments between lo and - hi. If either lo or hi occurs within a segment, they are - shifted out of it toward the other bound. */ - mlo = maps; - mhi = &maps[nmaps-1]; - while (mlo <= mhi) { - beg = BEG(mlo); - end = END(mlo); - - if (lo < beg) - break; - - if (lo >= beg && lo < end) - /* lo occurs in this segment. Shift lo to end of segment. */ - lo = end; /* still a page boundary */ - - ++mlo; - } - - while (mhi >= mlo) { - beg = BEG(mhi); - end = END(mhi); - - if (hi > end) - break; - if (hi >= beg && hi <= end) - /* hi occurs in this segment (or just after it). Shift - hi to beginning of segment. */ - hi = beg; /* still a page boundary */ - - --mhi; - } - if (lo >= hi) - return 0; - - /* We've set the bounds of the search, now go find some free space. */ - - /* Pathological cases in which the range (lo,hi) is entirely - above or below the rest of the address space, or there are no - segments between lo and hi. Return no matter what from - here. */ - if (BEG(mlo) >= hi || END(mhi) <= lo) { - return trymmap(len, lo, hi, psize, fd); - } - assert(lo < BEG(mlo) && hi > END(mhi)); - /* Try to mmap in space before mlo */ - try = trymmap(len, lo, BEG(mlo), psize, fd); - if (try) { - return try; - } - - /* Try to mmap in space between mlo and mhi. Try nothing here if - mlo and mhi are the same. */ - for (p = mlo; p < mhi; p++) { - try = trymmap(len, END(p), BEG(p+1), psize, fd); - if (try) - return try; - } - - /* Try to mmap in space between mhi and hi */ - try = trymmap(len, END(mhi), hi, psize, fd); - if (try) - return try; - - /* We've tried everything */ - return 0; -} -#undef BEG -#undef END - - -static int heap_memmapCompare(const void *A, const void *B) -{ - const dyninstmm_t *a = (const dyninstmm_t *)A; - const dyninstmm_t *b = (const dyninstmm_t *)B; - if (a->pr_vaddr < b->pr_vaddr) return -1; - if (a->pr_vaddr > b->pr_vaddr) return 1; - return 0; -} - void *DYNINSTos_malloc(size_t nbytes, void *lo_addr, void *hi_addr) { char *heap; From 1da19c163bdba09dcad22d796bb957c3015c3786 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 30 Jun 2016 12:18:05 -0400 Subject: [PATCH 033/180] Fix even more warnings --- dataflowAPI/src/stackanalysis.C | 10 +++++----- parseAPI/src/BoundFactData.C | 2 ++ parseAPI/src/IA_aarch64Details.C | 2 +- parseAPI/src/JumpTablePred.h | 4 +--- symtabAPI/src/Object-elf.C | 1 - symtabAPI/src/dwarfWalker.h | 25 +++++++++++++------------ 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 4cdce41fcd..2c54c61474 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -1016,7 +1016,7 @@ void StackAnalysis::handleXor(Instruction::Ptr insn, Block *block, // xor mem1, imm2 // Xor with immediate. Set topBottom on target loc Expression::Ptr immExpr = operands[1].getValue(); - assert(typeid(*immExpr) == typeid(Immediate)); + assert(dynamic_cast(immExpr.get())); xferFuncs.push_back(TransferFunc::copyFunc(writtenLoc, writtenLoc, true)); } @@ -1085,7 +1085,7 @@ void StackAnalysis::handleXor(Instruction::Ptr insn, Block *block, } else { // xor reg1, imm1 InstructionAPI::Expression::Ptr readExpr = operands[1].getValue(); - assert(typeid(*readExpr) == typeid(InstructionAPI::Immediate)); + assert(dynamic_cast(readExpr.get())); xferFuncs.push_back(TransferFunc::copyFunc(writtenLoc, writtenLoc, true)); copyBaseSubReg(written, xferFuncs); } @@ -1212,13 +1212,13 @@ void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, Absloc writtenLoc(writtenSlotHeight, 0, NULL); Expression::Ptr readExpr = insn->getOperand(0).getValue(); - if (typeid(*readExpr) == typeid(RegisterAST)) { + if (dynamic_cast(readExpr.get())) { // Get copied register MachRegister readReg = boost::dynamic_pointer_cast( readExpr)->getID(); Absloc readLoc(readReg); xferFuncs.push_back(TransferFunc::copyFunc(readLoc, writtenLoc)); - } else if (typeid(*readExpr) == typeid(Immediate)) { + } else if (dynamic_cast(readExpr.get())) { // Get pushed immediate long immVal = readExpr->eval().convert(); xferFuncs.push_back(TransferFunc::absFunc(writtenLoc, immVal)); @@ -1232,7 +1232,7 @@ void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, // Get target register Expression::Ptr targExpr = insn->getOperand(0).getValue(); - assert(typeid(*targExpr) == typeid(RegisterAST)); + assert(dynamic_cast(targExpr.get())); MachRegister targReg = boost::dynamic_pointer_cast( targExpr)->getID(); Absloc targLoc(targReg); diff --git a/parseAPI/src/BoundFactData.C b/parseAPI/src/BoundFactData.C index b787ff12ca..16de220cbb 100644 --- a/parseAPI/src/BoundFactData.C +++ b/parseAPI/src/BoundFactData.C @@ -797,6 +797,7 @@ void BoundFact::GenFact(const AST::Ptr ast, BoundValue* bv, bool isConditionalJu } } +/* static bool IsSubTree(AST::Ptr tree, AST::Ptr sub) { if (*tree == *sub) return true; bool ret = false; @@ -806,6 +807,7 @@ static bool IsSubTree(AST::Ptr tree, AST::Ptr sub) { } return ret; } +*/ void BoundFact::KillFact(const AST::Ptr ast, bool isConditionalJump) { for (auto fit = fact.begin(); fit != fact.end();) diff --git a/parseAPI/src/IA_aarch64Details.C b/parseAPI/src/IA_aarch64Details.C index e68a7d5852..2c6417b055 100644 --- a/parseAPI/src/IA_aarch64Details.C +++ b/parseAPI/src/IA_aarch64Details.C @@ -166,7 +166,7 @@ bool IA_aarch64Details::parseJumpTable(Block* /*currBlk*/, bool IA_aarch64Details::parseJumpTable(Dyninst::ParseAPI::Function* currFunc, Dyninst::ParseAPI::Block* currBlk, - std::vector >& outEdges) + std::vector >& outEdges) { IndirectControlFlowAnalyzer icfa(currFunc, currBlk); bool ret = icfa.NewJumpTableAnalysis(outEdges); diff --git a/parseAPI/src/JumpTablePred.h b/parseAPI/src/JumpTablePred.h index 90dee4cac9..ff207b2ca8 100644 --- a/parseAPI/src/JumpTablePred.h +++ b/parseAPI/src/JumpTablePred.h @@ -11,7 +11,6 @@ using namespace Dyninst; class JumpTablePred : public Slicer::Predicates { - bool firstMemoryRead; ParseAPI::Function *func; ParseAPI::Block *block; ReachFact &rf; @@ -40,8 +39,7 @@ GraphPtr BuildAnalysisGraph(std::set &visitedEdges); ReachFact &r, ThunkData &t, std::vector >& out): - firstMemoryRead(true), func(f), - block(b), rf(r), thunks(t), outEdges(out),jumpTableFormat(true) {} + func(f), block(b), rf(r), thunks(t), outEdges(out), jumpTableFormat(true) {} }; diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index ea0722a98a..3c4c303fde 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2428,7 +2428,6 @@ char ** declFileNoToName = NULL; bool Object::fix_global_symbol_modules_static_dwarf() { - int status; /* Initialize libdwarf. */ Dwarf_Debug *dbg_ptr = dwarf->type_dbg(); if (!dbg_ptr) diff --git a/symtabAPI/src/dwarfWalker.h b/symtabAPI/src/dwarfWalker.h index 9c5111e1b0..8ab7977485 100644 --- a/symtabAPI/src/dwarfWalker.h +++ b/symtabAPI/src/dwarfWalker.h @@ -47,9 +47,9 @@ namespace Dyninst { Dwarf_Debug dbg_; public: DwarfParseActions(Symtab* s, Dwarf_Debug d) : - symtab_(s), + mod_(NULL), dbg_(d), - mod_(NULL) + symtab_(s) {} typedef std::vector > range_set_t; typedef boost::shared_ptr > > range_set_ptr; @@ -373,7 +373,7 @@ namespace Dyninst { class ModuleFixer: public DwarfWalker { private: - virtual bool findType(Type *&type, bool defaultToVoid) { + virtual bool findType(Type *& /*type*/, bool /*defaultToVoid*/) { return false; } public: @@ -391,9 +391,9 @@ namespace Dyninst { return m_obj; } - virtual void createLocalVariable(const std::vector &locs, Type *type, - Dwarf_Unsigned variableLineNo, - const std::string &fileName) { + virtual void createLocalVariable(const std::vector & /*locs*/, Type * /*type*/, + Dwarf_Unsigned /*variableLineNo*/, + const std::string & /*fileName*/) { } @@ -405,8 +405,8 @@ namespace Dyninst { } - virtual void createParameter(const std::vector &locs, Type *paramType, Dwarf_Unsigned lineNo, - const std::string &fileName) { + virtual void createParameter(const std::vector & /*locs*/, Type * /*paramType*/, Dwarf_Unsigned /*lineNo*/, + const std::string & /*fileName*/) { } @@ -414,15 +414,16 @@ namespace Dyninst { } - virtual void createGlobalVariable(const std::vector &locs, Type *type) { + virtual void createGlobalVariable(const std::vector & /*locs*/, Type * /*type*/) { } - virtual bool addStaticClassVariable(const std::vector &locs, Type *type) { + virtual bool addStaticClassVariable(const std::vector & /*locs*/, Type * /*type*/) { + return false; } - virtual typeCommon *getCommonBlockType(std::string &commonBlockName) { + virtual typeCommon *getCommonBlockType(std::string & /*commonBlockName*/) { return NULL; } virtual void setModuleFromName(std::string moduleName) { @@ -430,7 +431,7 @@ namespace Dyninst { } - virtual Symbol *findSymbolForCommonBlock(const std::string &commonBlockName) { + virtual Symbol *findSymbolForCommonBlock(const std::string & /*commonBlockName*/) { return NULL; } virtual bool parseVariable() { From 09b01aa09079339b47b6bbaae8c9dedb682a56f6 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sat, 21 May 2016 16:35:13 -0400 Subject: [PATCH 034/180] cleanup DyninstRT cmake configuration --- CMakeLists.txt | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62d5e5ff52..673604452a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,21 +82,10 @@ if(${SYMREADER} MATCHES symtabAPI) add_subdirectory (dyninstAPI) endif() -# Build the RT library as a seperate project so we can change compilers -message(STATUS "Configuring DyninstAPI_RT") -file(REMOVE_RECURSE ${RT_BINARY_DIR}/CMakeCache.txt ${RT_BINARY_DIR}/CMakeFiles ${RT_BINARY_DIR}/Makefile ${RT_BINARY_DIR}/Makefile) -file(MAKE_DIRECTORY ${RT_BINARY_DIR}) -if (PLATFORM MATCHES bgq) - set (RT_C_COMPILER mpicc CACHE STRING "Compiler for runtime library") -else() - set (RT_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING "Compiler for runtime library") -endif() -set (ENABLE_STATIC_LIBS NO CACHE STRING "Build static libraries as well?") -message(STATUS "Configuring RT library") if(BUILD_RTLIB) - # Build the RT library as a seperate project so we can change compilers + # Build the RT library as a separate project so we can change compilers message(STATUS "Configuring DyninstAPI_RT") - file(REMOVE_RECURSE ${RT_BINARY_DIR}/CMakeCache.txt ${RT_BINARY_DIR}/CMakeFiles ${RT_BINARY_DIR}/Makefile ${RT_BINARY_DIR}/Makefile) + file(REMOVE_RECURSE ${RT_BINARY_DIR}/CMakeCache.txt ${RT_BINARY_DIR}/Makefile) file(MAKE_DIRECTORY ${RT_BINARY_DIR}) if (PLATFORM MATCHES bgq) set (RT_C_COMPILER mpicc CACHE STRING "Compiler for runtime library") From db6687b094bf42d71119d425c9305a87fd0218dd Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 30 Jun 2016 13:07:40 -0400 Subject: [PATCH 035/180] fix warning --- instructionAPI/src/InstructionDecoder-aarch64.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instructionAPI/src/InstructionDecoder-aarch64.C b/instructionAPI/src/InstructionDecoder-aarch64.C index a8e5e97e75..c8af4ddd8f 100644 --- a/instructionAPI/src/InstructionDecoder-aarch64.C +++ b/instructionAPI/src/InstructionDecoder-aarch64.C @@ -1075,7 +1075,7 @@ namespace Dyninst { Expression::Ptr label = Immediate::makeImmediate(Result(s64, sign_extend64(immLen, immVal))); - Result_Type rt; + Result_Type rt = invalid_type; getMemRefIndexLiteral_RT(rt); return makeDereferenceExpression(makeAddExpression(makePCExpr(), label, u64), rt); From f784936cb4ef395e0800283ba66239c151f4741e Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 6 May 2016 11:17:23 -0400 Subject: [PATCH 036/180] update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9e8b52ec58..95999f1137 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,5 @@ DyninstAPI*.tgz common/h/version.h Doxyfile doxyfiles/* +*/*.dir/ +*/Debug/ From 85e111c531176d2d6fb4f79315ee707a7e41b5f8 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 6 May 2016 10:54:43 -0400 Subject: [PATCH 037/180] add appveyor config --- appveyor.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..9b19cc77c1 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,19 @@ +build: + parallel: true + project: Dyninst.sln + verbosity: normal + +clone_depth: 5 + +platform: + - Win32 + +configuration: + - Release + +environment: + BOOST_ROOT: C:\Libraries\boost_1_60_0 + BOOST_LIBRARYDIR: C:\Libraries\boost_1_60_0\lib32-msvc-14.0 + +before_build: + - cmake . From a1fa7ed0a321d0cc1c60ca322f6346d1d7c0c517 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 6 May 2016 16:01:38 -0400 Subject: [PATCH 038/180] reduce warning spam from system headers --- cmake/warnings.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake index fd6fd14900..45497556a4 100644 --- a/cmake/warnings.cmake +++ b/cmake/warnings.cmake @@ -6,6 +6,6 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual") elseif (MSVC) message(STATUS "TODO: Set up custom warning flags for MSVC") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4251") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4251 /wd4091") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251 /wd4091") endif() From cdbbb60f3a12c103b1ee74775bdb91ea6973752a Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 13 May 2016 18:15:43 -0400 Subject: [PATCH 039/180] warnings --- dataflowAPI/src/SymEvalPolicy.C | 1 + dyninstAPI/src/Relocation/Widgets/CFWidget.C | 2 +- symtabAPI/src/Symtab-lookup.C | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dataflowAPI/src/SymEvalPolicy.C b/dataflowAPI/src/SymEvalPolicy.C index 5235246654..9eea90b2aa 100644 --- a/dataflowAPI/src/SymEvalPolicy.C +++ b/dataflowAPI/src/SymEvalPolicy.C @@ -350,6 +350,7 @@ Absloc SymEvalPolicy_64::convert(PowerpcRegisterClass regtype, int regNum) case powerpc_regclass_sr:break; case powerpc_last_register_class:break; } + assert(0); } Absloc SymEvalPolicy_64::convert(X86GeneralPurposeRegister r) diff --git a/dyninstAPI/src/Relocation/Widgets/CFWidget.C b/dyninstAPI/src/Relocation/Widgets/CFWidget.C index d0b39c88fa..c17cc829b4 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/CFWidget.C @@ -115,7 +115,7 @@ CFWidget::CFWidget(InstructionAPI::Instruction::Ptr insn, Address addr) : // I'm working around it here and in Movement-adhoc.C by checking _both_ // 32- and 64-bit. - Architecture fixme = insn_->getArch(); + //Architecture fixme = insn_->getArch(); //if (fixme == Arch_ppc32) fixme = Arch_ppc64; Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn_->getArch()))); diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 77785efb8f..0d014d960b 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -391,7 +391,7 @@ bool Symtab::findModuleByOffset(Module *&ret, Offset off) { std::sort(_mods.begin(), _mods.end(), module_less); // this should be a hash, really - for(int i = 0; i < _mods.size(); i++) + for(size_t i = 0; i < _mods.size(); i++) { // cout << *(_mods[i]) << endl; if(_mods[i]->addr() == off) From 525f2a1e5805d9992e71e286355deaeda9154996 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 13 May 2016 17:57:41 -0400 Subject: [PATCH 040/180] cotire --- .travis.yml | 2 +- cmake/cotire.cmake | 3917 +++++++++++++++++++++++++++++++++ cmake/shared.cmake | 1 + common/CMakeLists.txt | 1 + dwarf/CMakeLists.txt | 2 +- dynC_API/CMakeLists.txt | 1 + dyninstAPI/CMakeLists.txt | 1 + elf/CMakeLists.txt | 2 +- instructionAPI/CMakeLists.txt | 1 + parseAPI/CMakeLists.txt | 1 + patchAPI/CMakeLists.txt | 2 +- proccontrol/CMakeLists.txt | 1 + stackwalk/CMakeLists.txt | 2 +- symlite/CMakeLists.txt | 1 + symtabAPI/CMakeLists.txt | 2 +- 15 files changed, 3931 insertions(+), 6 deletions(-) create mode 100644 cmake/cotire.cmake diff --git a/.travis.yml b/.travis.yml index ca54653330..5a474aa9bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ env: addons: apt: sources: - - kalakris-cmake + - kubuntu-backports - ubuntu-toolchain-r-test - boost-latest packages: diff --git a/cmake/cotire.cmake b/cmake/cotire.cmake new file mode 100644 index 0000000000..741d6901f1 --- /dev/null +++ b/cmake/cotire.cmake @@ -0,0 +1,3917 @@ +# - cotire (compile time reducer) +# +# See the cotire manual for usage hints. +# +#============================================================================= +# Copyright 2012-2016 Sascha Kratky +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#============================================================================= + +if(__COTIRE_INCLUDED) + return() +endif() +set(__COTIRE_INCLUDED TRUE) + +# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode +# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid +if (NOT CMAKE_SCRIPT_MODE_FILE) + cmake_policy(PUSH) +endif() +cmake_minimum_required(VERSION 2.8.12) +if (NOT CMAKE_SCRIPT_MODE_FILE) + cmake_policy(POP) +endif() + +set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}") +set (COTIRE_CMAKE_MODULE_VERSION "1.7.8") + +# activate select policies +if (POLICY CMP0025) + # Compiler id for Apple Clang is now AppleClang + cmake_policy(SET CMP0025 NEW) +endif() + +if (POLICY CMP0026) + # disallow use of the LOCATION target property + cmake_policy(SET CMP0026 NEW) +endif() + +if (POLICY CMP0038) + # targets may not link directly to themselves + cmake_policy(SET CMP0038 NEW) +endif() + +if (POLICY CMP0039) + # utility targets may not have link dependencies + cmake_policy(SET CMP0039 NEW) +endif() + +if (POLICY CMP0040) + # target in the TARGET signature of add_custom_command() must exist + cmake_policy(SET CMP0040 NEW) +endif() + +if (POLICY CMP0045) + # error on non-existent target in get_target_property + cmake_policy(SET CMP0045 NEW) +endif() + +if (POLICY CMP0046) + # error on non-existent dependency in add_dependencies + cmake_policy(SET CMP0046 NEW) +endif() + +if (POLICY CMP0049) + # do not expand variables in target source entries + cmake_policy(SET CMP0049 NEW) +endif() + +if (POLICY CMP0050) + # disallow add_custom_command SOURCE signatures + cmake_policy(SET CMP0050 NEW) +endif() + +if (POLICY CMP0051) + # include TARGET_OBJECTS expressions in a target's SOURCES property + cmake_policy(SET CMP0051 NEW) +endif() + +if (POLICY CMP0053) + # simplify variable reference and escape sequence evaluation + cmake_policy(SET CMP0053 NEW) +endif() + +if (POLICY CMP0054) + # only interpret if() arguments as variables or keywords when unquoted + cmake_policy(SET CMP0054 NEW) +endif() + +include(CMakeParseArguments) +include(ProcessorCount) + +function (cotire_get_configuration_types _configsVar) + set (_configs "") + if (CMAKE_CONFIGURATION_TYPES) + list (APPEND _configs ${CMAKE_CONFIGURATION_TYPES}) + endif() + if (CMAKE_BUILD_TYPE) + list (APPEND _configs "${CMAKE_BUILD_TYPE}") + endif() + if (_configs) + list (REMOVE_DUPLICATES _configs) + set (${_configsVar} ${_configs} PARENT_SCOPE) + else() + set (${_configsVar} "None" PARENT_SCOPE) + endif() +endfunction() + +function (cotire_get_source_file_extension _sourceFile _extVar) + # get_filename_component returns extension from first occurrence of . in file name + # this function computes the extension from last occurrence of . in file name + string (FIND "${_sourceFile}" "." _index REVERSE) + if (_index GREATER -1) + math (EXPR _index "${_index} + 1") + string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt) + else() + set (_sourceExt "") + endif() + set (${_extVar} "${_sourceExt}" PARENT_SCOPE) +endfunction() + +macro (cotire_check_is_path_relative_to _path _isRelativeVar) + set (${_isRelativeVar} FALSE) + if (IS_ABSOLUTE "${_path}") + foreach (_dir ${ARGN}) + file (RELATIVE_PATH _relPath "${_dir}" "${_path}") + if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")) + set (${_isRelativeVar} TRUE) + break() + endif() + endforeach() + endif() +endmacro() + +function (cotire_filter_language_source_files _language _target _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar) + if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) + set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}") + else() + set (_languageExtensions "") + endif() + if (CMAKE_${_language}_IGNORE_EXTENSIONS) + set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}") + else() + set (_ignoreExtensions "") + endif() + if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS) + set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}") + else() + set (_excludeExtensions "") + endif() + if (COTIRE_DEBUG AND _languageExtensions) + message (STATUS "${_language} source file extensions: ${_languageExtensions}") + endif() + if (COTIRE_DEBUG AND _ignoreExtensions) + message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}") + endif() + if (COTIRE_DEBUG AND _excludeExtensions) + message (STATUS "${_language} exclude extensions: ${_excludeExtensions}") + endif() + if (CMAKE_VERSION VERSION_LESS "3.1.0") + set (_allSourceFiles ${ARGN}) + else() + # as of CMake 3.1 target sources may contain generator expressions + # since we cannot obtain required property information about source files added + # through generator expressions at configure time, we filter them out + string (GENEX_STRIP "${ARGN}" _allSourceFiles) + endif() + set (_filteredSourceFiles "") + set (_excludedSourceFiles "") + foreach (_sourceFile ${_allSourceFiles}) + get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY) + get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT) + get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC) + if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic) + cotire_get_source_file_extension("${_sourceFile}" _sourceExt) + if (_sourceExt) + list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex) + if (_ignoreIndex LESS 0) + list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex) + if (_excludeIndex GREATER -1) + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (FIND _languageExtensions "${_sourceExt}" _sourceIndex) + if (_sourceIndex GREATER -1) + # consider source file unless it is excluded explicitly + get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED) + if (_sourceIsExcluded) + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (APPEND _filteredSourceFiles "${_sourceFile}") + endif() + else() + get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE) + if ("${_sourceLanguage}" STREQUAL "${_language}") + # add to excluded sources, if file is not ignored and has correct language without having the correct extension + list (APPEND _excludedSourceFiles "${_sourceFile}") + endif() + endif() + endif() + endif() + endif() + endif() + endforeach() + # separate filtered source files from already cotired ones + # the COTIRE_TARGET property of a source file may be set while a target is being processed by cotire + set (_sourceFiles "") + set (_cotiredSourceFiles "") + foreach (_sourceFile ${_filteredSourceFiles}) + get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET) + if (_sourceIsCotired) + list (APPEND _cotiredSourceFiles "${_sourceFile}") + else() + get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS) + if (_sourceCompileFlags) + # add to excluded sources, if file has custom compile flags + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (APPEND _sourceFiles "${_sourceFile}") + endif() + endif() + endforeach() + if (COTIRE_DEBUG) + if (_sourceFiles) + message (STATUS "Filtered ${_target} ${_language} sources: ${_sourceFiles}") + endif() + if (_excludedSourceFiles) + message (STATUS "Excluded ${_target} ${_language} sources: ${_excludedSourceFiles}") + endif() + if (_cotiredSourceFiles) + message (STATUS "Cotired ${_target} ${_language} sources: ${_cotiredSourceFiles}") + endif() + endif() + set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE) + set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE) + set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE) +endfunction() + +function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type) + set (_filteredObjects "") + foreach (_object ${ARGN}) + get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (_propertyValue) + list (APPEND _filteredObjects "${_object}") + endif() + endif() + endforeach() + set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) +endfunction() + +function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type) + set (_filteredObjects "") + foreach (_object ${ARGN}) + get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (NOT _propertyValue) + list (APPEND _filteredObjects "${_object}") + endif() + endif() + endforeach() + set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_file_property_values _valuesVar _property) + set (_values "") + foreach (_sourceFile ${ARGN}) + get_source_file_property(_propertyValue "${_sourceFile}" ${_property}) + if (_propertyValue) + list (APPEND _values "${_propertyValue}") + endif() + endforeach() + set (${_valuesVar} ${_values} PARENT_SCOPE) +endfunction() + +function (cotire_resolve_config_properites _configurations _propertiesVar) + set (_properties "") + foreach (_property ${ARGN}) + if ("${_property}" MATCHES "") + foreach (_config ${_configurations}) + string (TOUPPER "${_config}" _upperConfig) + string (REPLACE "" "${_upperConfig}" _configProperty "${_property}") + list (APPEND _properties ${_configProperty}) + endforeach() + else() + list (APPEND _properties ${_property}) + endif() + endforeach() + set (${_propertiesVar} ${_properties} PARENT_SCOPE) +endfunction() + +function (cotire_copy_set_properites _configurations _type _source _target) + cotire_resolve_config_properites("${_configurations}" _properties ${ARGN}) + foreach (_property ${_properties}) + get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property}) + set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}") + endif() + endforeach() +endfunction() + +function (cotire_get_target_usage_requirements _target _targetRequirementsVar) + set (_targetRequirements "") + get_target_property(_librariesToProcess ${_target} LINK_LIBRARIES) + while (_librariesToProcess) + # remove from head + list (GET _librariesToProcess 0 _library) + list (REMOVE_AT _librariesToProcess 0) + if (TARGET ${_library}) + list (FIND _targetRequirements ${_library} _index) + if (_index LESS 0) + list (APPEND _targetRequirements ${_library}) + # BFS traversal of transitive libraries + get_target_property(_libraries ${_library} INTERFACE_LINK_LIBRARIES) + if (_libraries) + list (APPEND _librariesToProcess ${_libraries}) + list (REMOVE_DUPLICATES _librariesToProcess) + endif() + endif() + endif() + endwhile() + set (${_targetRequirementsVar} ${_targetRequirements} PARENT_SCOPE) +endfunction() + +function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + set (_flagPrefix "[/-]") + else() + set (_flagPrefix "--?") + endif() + set (_optionFlag "") + set (_matchedOptions "") + set (_unmatchedOptions "") + foreach (_compileFlag ${ARGN}) + if (_compileFlag) + if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}") + # option with separate argument + list (APPEND _matchedOptions "${_compileFlag}") + set (_optionFlag "") + elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$") + # remember option + set (_optionFlag "${CMAKE_MATCH_2}") + elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$") + # option with joined argument + list (APPEND _matchedOptions "${CMAKE_MATCH_3}") + set (_optionFlag "") + else() + # flush remembered option + if (_optionFlag) + list (APPEND _matchedOptions "${_optionFlag}") + set (_optionFlag "") + endif() + # add to unfiltered options + list (APPEND _unmatchedOptions "${_compileFlag}") + endif() + endif() + endforeach() + if (_optionFlag) + list (APPEND _matchedOptions "${_optionFlag}") + endif() + if (COTIRE_DEBUG AND _matchedOptions) + message (STATUS "Filter ${_flagFilter} matched: ${_matchedOptions}") + endif() + if (COTIRE_DEBUG AND _unmatchedOptions) + message (STATUS "Filter ${_flagFilter} unmatched: ${_unmatchedOptions}") + endif() + set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE) + set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE) +endfunction() + +function (cotire_is_target_supported _target _isSupportedVar) + if (NOT TARGET "${_target}") + set (${_isSupportedVar} FALSE PARENT_SCOPE) + return() + endif() + get_target_property(_imported ${_target} IMPORTED) + if (_imported) + set (${_isSupportedVar} FALSE PARENT_SCOPE) + return() + endif() + get_target_property(_targetType ${_target} TYPE) + if (NOT _targetType MATCHES "EXECUTABLE|(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") + set (${_isSupportedVar} FALSE PARENT_SCOPE) + return() + endif() + set (${_isSupportedVar} TRUE PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compile_flags _config _language _target _flagsVar) + string (TOUPPER "${_config}" _upperConfig) + # collect options from CMake language variables + set (_compileFlags "") + if (CMAKE_${_language}_FLAGS) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}") + endif() + if (CMAKE_${_language}_FLAGS_${_upperConfig}) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}") + endif() + if (_target) + # add target compile flags + get_target_property(_targetflags ${_target} COMPILE_FLAGS) + if (_targetflags) + set (_compileFlags "${_compileFlags} ${_targetflags}") + endif() + endif() + if (UNIX) + separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}") + elseif(WIN32) + separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}") + else() + separate_arguments(_compileFlags) + endif() + # target compile options + if (_target) + get_target_property(_targetOptions ${_target} COMPILE_OPTIONS) + if (_targetOptions) + list (APPEND _compileFlags ${_targetOptions}) + endif() + endif() + # interface compile options from linked library targets + if (_target) + set (_linkedTargets "") + cotire_get_target_usage_requirements(${_target} _linkedTargets) + foreach (_linkedTarget ${_linkedTargets}) + get_target_property(_targetOptions ${_linkedTarget} INTERFACE_COMPILE_OPTIONS) + if (_targetOptions) + list (APPEND _compileFlags ${_targetOptions}) + endif() + endforeach() + endif() + # handle language standard properties + if (_target) + get_target_property(_targetLanguageStandard ${_target} ${_language}_STANDARD) + get_target_property(_targetLanguageExtensions ${_target} ${_language}_EXTENSIONS) + get_target_property(_targetLanguageStandardRequired ${_target} ${_language}_STANDARD_REQUIRED) + if (_targetLanguageExtensions) + if (CMAKE_${_language}${_targetLanguageExtensions}_EXTENSION_COMPILE_OPTION) + list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageExtensions}_EXTENSION_COMPILE_OPTION}") + endif() + elseif (_targetLanguageStandard) + if (_targetLanguageStandardRequired) + if (CMAKE_${_language}${_targetLanguageStandard}_STANDARD_COMPILE_OPTION) + list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_STANDARD_COMPILE_OPTION}") + endif() + else() + if (CMAKE_${_language}${_targetLanguageStandard}_EXTENSION_COMPILE_OPTION) + list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_EXTENSION_COMPILE_OPTION}") + endif() + endif() + endif() + endif() + # handle the POSITION_INDEPENDENT_CODE target property + if (_target) + get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE) + if (_targetPIC) + get_target_property(_targetType ${_target} TYPE) + if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIE}") + elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIC}") + endif() + endif() + endif() + # handle visibility target properties + if (_target) + get_target_property(_targetVisibility ${_target} ${_language}_VISIBILITY_PRESET) + if (_targetVisibility AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY}${_targetVisibility}") + endif() + get_target_property(_targetVisibilityInlines ${_target} VISIBILITY_INLINES_HIDDEN) + if (_targetVisibilityInlines AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN}") + endif() + endif() + # platform specific flags + if (APPLE) + get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig}) + if (NOT _architectures) + get_target_property(_architectures ${_target} OSX_ARCHITECTURES) + endif() + if (_architectures) + foreach (_arch ${_architectures}) + list (APPEND _compileFlags "-arch" "${_arch}") + endforeach() + endif() + if (CMAKE_OSX_SYSROOT) + if (CMAKE_${_language}_SYSROOT_FLAG) + list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}") + else() + list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}") + endif() + endif() + if (CMAKE_OSX_DEPLOYMENT_TARGET) + if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG) + list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") + else() + list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") + endif() + endif() + endif() + if (COTIRE_DEBUG AND _compileFlags) + message (STATUS "Target ${_target} compile flags: ${_compileFlags}") + endif() + set (${_flagsVar} ${_compileFlags} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_include_directories _config _language _target _includeDirsVar _systemIncludeDirsVar) + set (_includeDirs "") + set (_systemIncludeDirs "") + # default include dirs + if (CMAKE_INCLUDE_CURRENT_DIR) + list (APPEND _includeDirs "${CMAKE_CURRENT_BINARY_DIR}") + list (APPEND _includeDirs "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + # parse additional include directories from target compile flags + if (CMAKE_INCLUDE_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_dirs "") + cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) + if (_dirs) + list (APPEND _includeDirs ${_dirs}) + endif() + endif() + endif() + # parse additional system include directories from target compile flags + if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_dirs "") + cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) + if (_dirs) + list (APPEND _systemIncludeDirs ${_dirs}) + endif() + endif() + endif() + # target include directories + get_directory_property(_dirs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" INCLUDE_DIRECTORIES) + if (_target) + get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _systemIncludeDirs ${_targetDirs}) + endif() + endif() + # interface include directories from linked library targets + if (_target) + set (_linkedTargets "") + cotire_get_target_usage_requirements(${_target} _linkedTargets) + foreach (_linkedTarget ${_linkedTargets}) + get_target_property(_linkedTargetType ${_linkedTarget} TYPE) + if (CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE AND NOT CMAKE_VERSION VERSION_LESS "3.4.0" AND + _linkedTargetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") + # CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE refers to CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR + # at the time, when the target was created. These correspond to the target properties BINARY_DIR and SOURCE_DIR + # which are only available with CMake 3.4 or later. + get_target_property(_targetDirs ${_linkedTarget} BINARY_DIR) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_linkedTarget} SOURCE_DIR) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + endif() + get_target_property(_targetDirs ${_linkedTarget} INTERFACE_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_linkedTarget} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _systemIncludeDirs ${_targetDirs}) + endif() + endforeach() + endif() + if (dirs) + list (REMOVE_DUPLICATES _dirs) + endif() + list (LENGTH _includeDirs _projectInsertIndex) + foreach (_dir ${_dirs}) + if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE) + cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}") + if (_isRelative) + list (LENGTH _includeDirs _len) + if (_len EQUAL _projectInsertIndex) + list (APPEND _includeDirs "${_dir}") + else() + list (INSERT _includeDirs _projectInsertIndex "${_dir}") + endif() + math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1") + else() + list (APPEND _includeDirs "${_dir}") + endif() + else() + list (APPEND _includeDirs "${_dir}") + endif() + endforeach() + list (REMOVE_DUPLICATES _includeDirs) + list (REMOVE_DUPLICATES _systemIncludeDirs) + if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES) + list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES}) + endif() + if (COTIRE_DEBUG AND _includeDirs) + message (STATUS "Target ${_target} include dirs: ${_includeDirs}") + endif() + set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE) + if (COTIRE_DEBUG AND _systemIncludeDirs) + message (STATUS "Target ${_target} system include dirs: ${_systemIncludeDirs}") + endif() + set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_export_symbol _target _exportSymbolVar) + set (_exportSymbol "") + get_target_property(_targetType ${_target} TYPE) + get_target_property(_enableExports ${_target} ENABLE_EXPORTS) + if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR + (_targetType STREQUAL "EXECUTABLE" AND _enableExports)) + get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL) + if (NOT _exportSymbol) + set (_exportSymbol "${_target}_EXPORTS") + endif() + string (MAKE_C_IDENTIFIER "${_exportSymbol}" _exportSymbol) + endif() + set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compile_definitions _config _language _target _definitionsVar) + string (TOUPPER "${_config}" _upperConfig) + set (_configDefinitions "") + # CMAKE_INTDIR for multi-configuration build systems + if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") + list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"") + endif() + # target export define symbol + cotire_get_target_export_symbol("${_target}" _defineSymbol) + if (_defineSymbol) + list (APPEND _configDefinitions "${_defineSymbol}") + endif() + # directory compile definitions + get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + # target compile definitions + get_target_property(_definitions ${_target} COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + # interface compile definitions from linked library targets + set (_linkedTargets "") + cotire_get_target_usage_requirements(${_target} _linkedTargets) + foreach (_linkedTarget ${_linkedTargets}) + get_target_property(_definitions ${_linkedTarget} INTERFACE_COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + endforeach() + # parse additional compile definitions from target compile flags + # and don't look at directory compile definitions, which we already handled + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + list (REMOVE_DUPLICATES _configDefinitions) + if (COTIRE_DEBUG AND _configDefinitions) + message (STATUS "Target ${_target} compile definitions: ${_configDefinitions}") + endif() + set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compiler_flags _config _language _target _compilerFlagsVar) + # parse target compile flags omitting compile definitions and include directives + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + set (_flagFilter "D") + if (CMAKE_INCLUDE_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_flagFilter "${_flagFilter}|${_includeFlag}") + endif() + endif() + if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_flagFilter "${_flagFilter}|${_includeFlag}") + endif() + endif() + set (_compilerFlags "") + cotire_filter_compile_flags("${_language}" "${_flagFilter}" _ignore _compilerFlags ${_targetFlags}) + if (COTIRE_DEBUG AND _compilerFlags) + message (STATUS "Target ${_target} compiler flags: ${_compilerFlags}") + endif() + set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE) +endfunction() + +function (cotire_add_sys_root_paths _pathsVar) + if (APPLE) + if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT) + foreach (_path IN LISTS ${_pathsVar}) + if (IS_ABSOLUTE "${_path}") + get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE) + if (EXISTS "${_path}") + list (APPEND ${_pathsVar} "${_path}") + endif() + endif() + endforeach() + endif() + endif() + set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar) + set (_extraProperties ${ARGN}) + set (_result "") + if (_extraProperties) + list (FIND _extraProperties "${_sourceFile}" _index) + if (_index GREATER -1) + math (EXPR _index "${_index} + 1") + list (LENGTH _extraProperties _len) + math (EXPR _len "${_len} - 1") + foreach (_index RANGE ${_index} ${_len}) + list (GET _extraProperties ${_index} _value) + if (_value MATCHES "${_pattern}") + list (APPEND _result "${_value}") + else() + break() + endif() + endforeach() + endif() + endif() + set (${_resultVar} ${_result} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar) + set (_compileDefinitions "") + if (NOT CMAKE_SCRIPT_MODE_FILE) + string (TOUPPER "${_config}" _upperConfig) + get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + endif() + cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN}) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + if (COTIRE_DEBUG AND _compileDefinitions) + message (STATUS "Source ${_sourceFile} compile definitions: ${_compileDefinitions}") + endif() + set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_files_compile_definitions _config _language _definitionsVar) + set (_configDefinitions "") + foreach (_sourceFile ${ARGN}) + cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions) + if (_sourceDefinitions) + list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-") + endif() + endforeach() + set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar) + set (_sourceUndefs "") + if (NOT CMAKE_SCRIPT_MODE_FILE) + get_source_file_property(_undefs "${_sourceFile}" ${_property}) + if (_undefs) + list (APPEND _sourceUndefs ${_undefs}) + endif() + endif() + cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN}) + if (_undefs) + list (APPEND _sourceUndefs ${_undefs}) + endif() + if (COTIRE_DEBUG AND _sourceUndefs) + message (STATUS "Source ${_sourceFile} ${_property} undefs: ${_sourceUndefs}") + endif() + set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_files_undefs _property _sourceUndefsVar) + set (_sourceUndefs "") + foreach (_sourceFile ${ARGN}) + cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs) + if (_undefs) + list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-") + endif() + endforeach() + set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) +endfunction() + +macro (cotire_set_cmd_to_prologue _cmdVar) + set (${_cmdVar} "${CMAKE_COMMAND}") + if (COTIRE_DEBUG) + list (APPEND ${_cmdVar} "--warn-uninitialized") + endif() + list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$") + if (COTIRE_VERBOSE) + list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON") + elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles") + list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)") + endif() +endmacro() + +function (cotire_init_compile_cmd _cmdVar _language _compilerLauncher _compilerExe _compilerArg1) + if (NOT _compilerLauncher) + set (_compilerLauncher ${CMAKE_${_language}_COMPILER_LAUNCHER}) + endif() + if (NOT _compilerExe) + set (_compilerExe "${CMAKE_${_language}_COMPILER}") + endif() + if (NOT _compilerArg1) + set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1}) + endif() + string (STRIP "${_compilerArg1}" _compilerArg1) + if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # compiler launcher is only supported for Makefile and Ninja + set (${_cmdVar} ${_compilerLauncher} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) + else() + set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) + endif() +endfunction() + +macro (cotire_add_definitions_to_cmd _cmdVar _language) + foreach (_definition ${ARGN}) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + list (APPEND ${_cmdVar} "/D${_definition}") + else() + list (APPEND ${_cmdVar} "-D${_definition}") + endif() + endforeach() +endmacro() + +function (cotire_add_includes_to_cmd _cmdVar _language _includesVar _systemIncludesVar) + set (_includeDirs ${${_includesVar}} ${${_systemIncludesVar}}) + if (_includeDirs) + list (REMOVE_DUPLICATES _includeDirs) + foreach (_include ${_includeDirs}) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + file (TO_NATIVE_PATH "${_include}" _include) + list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}") + else() + set (_index -1) + if ("${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" MATCHES ".+") + list (FIND ${_systemIncludesVar} "${_include}" _index) + endif() + if (_index GREATER -1) + list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}${_include}") + else() + list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}") + endif() + endif() + endforeach() + endif() + set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) +endfunction() + +function (cotire_add_frameworks_to_cmd _cmdVar _language _includesVar _systemIncludesVar) + if (APPLE) + set (_frameworkDirs "") + foreach (_include ${${_includesVar}}) + if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") + get_filename_component(_frameworkDir "${_include}" DIRECTORY) + list (APPEND _frameworkDirs "${_frameworkDir}") + endif() + endforeach() + set (_systemFrameworkDirs "") + foreach (_include ${${_systemIncludesVar}}) + if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") + get_filename_component(_frameworkDir "${_include}" DIRECTORY) + list (APPEND _systemFrameworkDirs "${_frameworkDir}") + endif() + endforeach() + if (_systemFrameworkDirs) + list (APPEND _frameworkDirs ${_systemFrameworkDirs}) + endif() + if (_frameworkDirs) + list (REMOVE_DUPLICATES _frameworkDirs) + foreach (_frameworkDir ${_frameworkDirs}) + set (_index -1) + if ("${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}" MATCHES ".+") + list (FIND _systemFrameworkDirs "${_frameworkDir}" _index) + endif() + if (_index GREATER -1) + list (APPEND ${_cmdVar} "${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") + else() + list (APPEND ${_cmdVar} "${CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") + endif() + endforeach() + endif() + endif() + set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) +endfunction() + +macro (cotire_add_compile_flags_to_cmd _cmdVar) + foreach (_flag ${ARGN}) + list (APPEND ${_cmdVar} "${_flag}") + endforeach() +endmacro() + +function (cotire_check_file_up_to_date _fileIsUpToDateVar _file) + if (EXISTS "${_file}") + set (_triggerFile "") + foreach (_dependencyFile ${ARGN}) + if (EXISTS "${_dependencyFile}") + # IS_NEWER_THAN returns TRUE if both files have the same timestamp + # thus we do the comparison in both directions to exclude ties + if ("${_dependencyFile}" IS_NEWER_THAN "${_file}" AND + NOT "${_file}" IS_NEWER_THAN "${_dependencyFile}") + set (_triggerFile "${_dependencyFile}") + break() + endif() + endif() + endforeach() + if (_triggerFile) + if (COTIRE_VERBOSE) + get_filename_component(_fileName "${_file}" NAME) + message (STATUS "${_fileName} update triggered by ${_triggerFile} change.") + endif() + set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) + else() + if (COTIRE_VERBOSE) + get_filename_component(_fileName "${_file}" NAME) + message (STATUS "${_fileName} is up-to-date.") + endif() + set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE) + endif() + else() + if (COTIRE_VERBOSE) + get_filename_component(_fileName "${_file}" NAME) + message (STATUS "${_fileName} does not exist yet.") + endif() + set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) + endif() +endfunction() + +macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar) + set (${_relPathVar} "") + foreach (_includeDir ${_includeDirs}) + if (IS_DIRECTORY "${_includeDir}") + file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}") + if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.") + string (LENGTH "${${_relPathVar}}" _closestLen) + string (LENGTH "${_relPath}" _relLen) + if (_closestLen EQUAL 0 OR _relLen LESS _closestLen) + set (${_relPathVar} "${_relPath}") + endif() + endif() + elseif ("${_includeDir}" STREQUAL "${_headerFile}") + # if path matches exactly, return short non-empty string + set (${_relPathVar} "1") + break() + endif() + endforeach() +endmacro() + +macro (cotire_check_header_file_location _headerFile _insideIncludeDirs _outsideIncludeDirs _headerIsInside) + # check header path against ignored and honored include directories + cotire_find_closest_relative_path("${_headerFile}" "${_insideIncludeDirs}" _insideRelPath) + if (_insideRelPath) + # header is inside, but could be become outside if there is a shorter outside match + cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncludeDirs}" _outsideRelPath) + if (_outsideRelPath) + string (LENGTH "${_insideRelPath}" _insideRelPathLen) + string (LENGTH "${_outsideRelPath}" _outsideRelPathLen) + if (_outsideRelPathLen LESS _insideRelPathLen) + set (${_headerIsInside} FALSE) + else() + set (${_headerIsInside} TRUE) + endif() + else() + set (${_headerIsInside} TRUE) + endif() + else() + # header is outside + set (${_headerIsInside} FALSE) + endif() +endmacro() + +macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar) + if (NOT EXISTS "${_headerFile}") + set (${_headerIsIgnoredVar} TRUE) + elseif (IS_DIRECTORY "${_headerFile}") + set (${_headerIsIgnoredVar} TRUE) + elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$") + # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path + # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation + # with the error message "error: no include path in which to search for header.h" + set (${_headerIsIgnoredVar} TRUE) + else() + set (${_headerIsIgnoredVar} FALSE) + endif() +endmacro() + +macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar) + # check header file extension + cotire_get_source_file_extension("${_headerFile}" _headerFileExt) + set (${_headerIsIgnoredVar} FALSE) + if (_headerFileExt) + list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index) + if (_index GREATER -1) + set (${_headerIsIgnoredVar} TRUE) + endif() + endif() +endmacro() + +macro (cotire_parse_line _line _headerFileVar _headerDepthVar) + if (MSVC) + # cl.exe /showIncludes output looks different depending on the language pack used, e.g.: + # English: "Note: including file: C:\directory\file" + # German: "Hinweis: Einlesen der Datei: C:\directory\file" + # We use a very general regular expression, relying on the presence of the : characters + if (_line MATCHES "( +)([a-zA-Z]:[^:]+)$") + # Visual Studio compiler output + string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) + get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE) + else() + set (${_headerFileVar} "") + set (${_headerDepthVar} 0) + endif() + else() + if (_line MATCHES "^(\\.+) (.*)$") + # GCC like output + string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) + if (IS_ABSOLUTE "${CMAKE_MATCH_2}") + set (${_headerFileVar} "${CMAKE_MATCH_2}") + else() + get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH) + endif() + else() + set (${_headerFileVar} "") + set (${_headerDepthVar} 0) + endif() + endif() +endmacro() + +function (cotire_parse_includes _language _scanOutput _ignoredIncludeDirs _honoredIncludeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar) + if (WIN32) + # prevent CMake macro invocation errors due to backslash characters in Windows paths + string (REPLACE "\\" "/" _scanOutput "${_scanOutput}") + endif() + # canonize slashes + string (REPLACE "//" "/" _scanOutput "${_scanOutput}") + # prevent semicolon from being interpreted as a line separator + string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}") + # then separate lines + string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}") + list (LENGTH _scanOutput _len) + # remove duplicate lines to speed up parsing + list (REMOVE_DUPLICATES _scanOutput) + list (LENGTH _scanOutput _uniqueLen) + if (COTIRE_VERBOSE OR COTIRE_DEBUG) + message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes") + if (_ignoredExtensions) + message (STATUS "Ignored extensions: ${_ignoredExtensions}") + endif() + if (_ignoredIncludeDirs) + message (STATUS "Ignored paths: ${_ignoredIncludeDirs}") + endif() + if (_honoredIncludeDirs) + message (STATUS "Included paths: ${_honoredIncludeDirs}") + endif() + endif() + set (_sourceFiles ${ARGN}) + set (_selectedIncludes "") + set (_unparsedLines "") + # stack keeps track of inside/outside project status of processed header files + set (_headerIsInsideStack "") + foreach (_line IN LISTS _scanOutput) + if (_line) + cotire_parse_line("${_line}" _headerFile _headerDepth) + if (_headerFile) + cotire_check_header_file_location("${_headerFile}" "${_ignoredIncludeDirs}" "${_honoredIncludeDirs}" _headerIsInside) + if (COTIRE_DEBUG) + message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}") + endif() + # update stack + list (LENGTH _headerIsInsideStack _stackLen) + if (_headerDepth GREATER _stackLen) + math (EXPR _stackLen "${_stackLen} + 1") + foreach (_index RANGE ${_stackLen} ${_headerDepth}) + list (APPEND _headerIsInsideStack ${_headerIsInside}) + endforeach() + else() + foreach (_index RANGE ${_headerDepth} ${_stackLen}) + list (REMOVE_AT _headerIsInsideStack -1) + endforeach() + list (APPEND _headerIsInsideStack ${_headerIsInside}) + endif() + if (COTIRE_DEBUG) + message (STATUS "${_headerIsInsideStack}") + endif() + # header is a candidate if it is outside project + if (NOT _headerIsInside) + # get parent header file's inside/outside status + if (_headerDepth GREATER 1) + math (EXPR _index "${_headerDepth} - 2") + list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside) + else() + set (_parentHeaderIsInside TRUE) + endif() + # select header file if parent header file is inside project + # (e.g., a project header file that includes a standard header file) + if (_parentHeaderIsInside) + cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored) + if (NOT _headerIsIgnored) + cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored) + if (NOT _headerIsIgnored) + list (APPEND _selectedIncludes "${_headerFile}") + else() + # fix header's inside status on stack, it is ignored by extension now + list (REMOVE_AT _headerIsInsideStack -1) + list (APPEND _headerIsInsideStack TRUE) + endif() + endif() + if (COTIRE_DEBUG) + message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}") + endif() + endif() + endif() + else() + if (MSVC) + # for cl.exe do not keep unparsed lines which solely consist of a source file name + string (FIND "${_sourceFiles}" "${_line}" _index) + if (_index LESS 0) + list (APPEND _unparsedLines "${_line}") + endif() + else() + list (APPEND _unparsedLines "${_line}") + endif() + endif() + endif() + endforeach() + list (REMOVE_DUPLICATES _selectedIncludes) + set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE) + set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE) +endfunction() + +function (cotire_scan_includes _includesVar) + set(_options "") + set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_VERSION LANGUAGE UNPARSED_LINES) + set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES + IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + if (NOT _option_LANGUAGE) + set (_option_LANGUAGE "CXX") + endif() + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + if (NOT _option_COMPILER_VERSION) + set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") + endif() + cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") + cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) + cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) + cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd) + # only consider existing source files for scanning + set (_existingSourceFiles "") + foreach (_sourceFile ${_sourceFiles}) + if (EXISTS "${_sourceFile}") + list (APPEND _existingSourceFiles "${_sourceFile}") + endif() + endforeach() + if (NOT _existingSourceFiles) + set (${_includesVar} "" PARENT_SCOPE) + return() + endif() + list (APPEND _cmd ${_existingSourceFiles}) + if (COTIRE_VERBOSE) + message (STATUS "execute_process: ${_cmd}") + endif() + if (_option_COMPILER_ID MATCHES "MSVC") + # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared + unset (ENV{VS_UNICODE_OUTPUT}) + endif() + execute_process( + COMMAND ${_cmd} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE _result + OUTPUT_QUIET + ERROR_VARIABLE _output) + if (_result) + message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.") + endif() + cotire_parse_includes( + "${_option_LANGUAGE}" "${_output}" + "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}" + "${_option_IGNORE_EXTENSIONS}" + _includes _unparsedLines + ${_sourceFiles}) + if (_option_INCLUDE_PRIORITY_PATH) + set (_sortedIncludes "") + foreach (_priorityPath ${_option_INCLUDE_PRIORITY_PATH}) + foreach (_include ${_includes}) + string (FIND ${_include} ${_priorityPath} _position) + if (_position GREATER -1) + list (APPEND _sortedIncludes ${_include}) + endif() + endforeach() + endforeach() + if (_sortedIncludes) + list (INSERT _includes 0 ${_sortedIncludes}) + list (REMOVE_DUPLICATES _includes) + endif() + endif() + set (${_includesVar} ${_includes} PARENT_SCOPE) + if (_option_UNPARSED_LINES) + set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE) + endif() +endfunction() + +macro (cotire_append_undefs _contentsVar) + set (_undefs ${ARGN}) + if (_undefs) + list (REMOVE_DUPLICATES _undefs) + foreach (_definition ${_undefs}) + list (APPEND ${_contentsVar} "#undef ${_definition}") + endforeach() + endif() +endmacro() + +macro (cotire_comment_str _language _commentText _commentVar) + if ("${_language}" STREQUAL "CMAKE") + set (${_commentVar} "# ${_commentText}") + else() + set (${_commentVar} "/* ${_commentText} */") + endif() +endmacro() + +function (cotire_write_file _language _file _contents _force) + get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) + cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1) + cotire_comment_str("${_language}" "${_file}" _header2) + set (_contents "${_header1}\n${_header2}\n${_contents}") + if (COTIRE_DEBUG) + message (STATUS "${_contents}") + endif() + if (_force OR NOT EXISTS "${_file}") + file (WRITE "${_file}" "${_contents}") + else() + file (READ "${_file}" _oldContents) + if (NOT "${_oldContents}" STREQUAL "${_contents}") + file (WRITE "${_file}" "${_contents}") + else() + if (COTIRE_DEBUG) + message (STATUS "${_file} unchanged") + endif() + endif() + endif() +endfunction() + +function (cotire_generate_unity_source _unityFile) + set(_options "") + set(_oneValueArgs LANGUAGE) + set(_multiValueArgs + DEPENDS SOURCES_COMPILE_DEFINITIONS + PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (_option_DEPENDS) + cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS}) + if (_unityFileIsUpToDate) + return() + endif() + endif() + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + if (NOT _option_PRE_UNDEFS) + set (_option_PRE_UNDEFS "") + endif() + if (NOT _option_SOURCES_PRE_UNDEFS) + set (_option_SOURCES_PRE_UNDEFS "") + endif() + if (NOT _option_POST_UNDEFS) + set (_option_POST_UNDEFS "") + endif() + if (NOT _option_SOURCES_POST_UNDEFS) + set (_option_SOURCES_POST_UNDEFS "") + endif() + set (_contents "") + if (_option_PROLOGUE) + list (APPEND _contents ${_option_PROLOGUE}) + endif() + if (_option_LANGUAGE AND _sourceFiles) + if ("${_option_LANGUAGE}" STREQUAL "CXX") + list (APPEND _contents "#ifdef __cplusplus") + elseif ("${_option_LANGUAGE}" STREQUAL "C") + list (APPEND _contents "#ifndef __cplusplus") + endif() + endif() + set (_compileUndefinitions "") + foreach (_sourceFile ${_sourceFiles}) + cotire_get_source_compile_definitions( + "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions + ${_option_SOURCES_COMPILE_DEFINITIONS}) + cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS}) + cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS}) + if (_option_PRE_UNDEFS) + list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS}) + endif() + if (_sourcePreUndefs) + list (APPEND _compileUndefinitions ${_sourcePreUndefs}) + endif() + if (_compileUndefinitions) + cotire_append_undefs(_contents ${_compileUndefinitions}) + set (_compileUndefinitions "") + endif() + if (_sourcePostUndefs) + list (APPEND _compileUndefinitions ${_sourcePostUndefs}) + endif() + if (_option_POST_UNDEFS) + list (APPEND _compileUndefinitions ${_option_POST_UNDEFS}) + endif() + foreach (_definition ${_compileDefinitions}) + if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$") + list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}") + list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}") + else() + list (APPEND _contents "#define ${_definition}") + list (INSERT _compileUndefinitions 0 "${_definition}") + endif() + endforeach() + # use absolute path as source file location + get_filename_component(_sourceFileLocation "${_sourceFile}" ABSOLUTE) + if (WIN32) + file (TO_NATIVE_PATH "${_sourceFileLocation}" _sourceFileLocation) + endif() + list (APPEND _contents "#include \"${_sourceFileLocation}\"") + endforeach() + if (_compileUndefinitions) + cotire_append_undefs(_contents ${_compileUndefinitions}) + set (_compileUndefinitions "") + endif() + if (_option_LANGUAGE AND _sourceFiles) + list (APPEND _contents "#endif") + endif() + if (_option_EPILOGUE) + list (APPEND _contents ${_option_EPILOGUE}) + endif() + list (APPEND _contents "") + string (REPLACE ";" "\n" _contents "${_contents}") + if (COTIRE_VERBOSE) + message ("${_contents}") + endif() + cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE) +endfunction() + +function (cotire_generate_prefix_header _prefixFile) + set(_options "") + set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION) + set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS + INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH + IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + if (NOT _option_COMPILER_VERSION) + set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") + endif() + if (_option_DEPENDS) + cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS}) + if (_prefixFileIsUpToDate) + # create empty log file + set (_unparsedLinesFile "${_prefixFile}.log") + file (WRITE "${_unparsedLinesFile}" "") + return() + endif() + endif() + set (_prologue "") + set (_epilogue "") + if (_option_COMPILER_ID MATCHES "Clang") + set (_prologue "#pragma clang system_header") + elseif (_option_COMPILER_ID MATCHES "GNU") + set (_prologue "#pragma GCC system_header") + elseif (_option_COMPILER_ID MATCHES "MSVC") + set (_prologue "#pragma warning(push, 0)") + set (_epilogue "#pragma warning(pop)") + elseif (_option_COMPILER_ID MATCHES "Intel") + # Intel compiler requires hdrstop pragma to stop generating PCH file + set (_epilogue "#pragma hdrstop") + endif() + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + cotire_scan_includes(_selectedHeaders ${_sourceFiles} + LANGUAGE "${_option_LANGUAGE}" + COMPILER_LAUNCHER "${_option_COMPILER_LAUNCHER}" + COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}" + COMPILER_ARG1 "${_option_COMPILER_ARG1}" + COMPILER_ID "${_option_COMPILER_ID}" + COMPILER_VERSION "${_option_COMPILER_VERSION}" + COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS} + COMPILE_FLAGS ${_option_COMPILE_FLAGS} + INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES} + SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES} + IGNORE_PATH ${_option_IGNORE_PATH} + INCLUDE_PATH ${_option_INCLUDE_PATH} + IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS} + INCLUDE_PRIORITY_PATH ${_option_INCLUDE_PRIORITY_PATH} + UNPARSED_LINES _unparsedLines) + cotire_generate_unity_source("${_prefixFile}" + PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders}) + set (_unparsedLinesFile "${_prefixFile}.log") + if (_unparsedLines) + if (COTIRE_VERBOSE OR NOT _selectedHeaders) + list (LENGTH _unparsedLines _skippedLineCount) + message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFile}") + endif() + string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}") + endif() + file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}") +endfunction() + +function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + # cl.exe options used + # /nologo suppresses display of sign-on banner + # /TC treat all files named on the command line as C source files + # /TP treat all files named on the command line as C++ source files + # /EP preprocess to stdout without #line directives + # /showIncludes list include files + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes) + else() + # return as a flag string + set (_flags "${_sourceFileType${_language}} /EP /showIncludes") + endif() + elseif (_compilerID MATCHES "GNU") + # GCC options used + # -H print the name of each header file used + # -E invoke preprocessor + # -fdirectives-only do not expand macros, requires GCC >= 4.3 + if (_flags) + # append to list + list (APPEND _flags -H -E) + if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") + list (APPEND _flags "-fdirectives-only") + endif() + else() + # return as a flag string + set (_flags "-H -E") + if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") + set (_flags "${_flags} -fdirectives-only") + endif() + endif() + elseif (_compilerID MATCHES "Clang") + # Clang options used + # -H print the name of each header file used + # -E invoke preprocessor + # -fno-color-diagnostics don't prints diagnostics in color + if (_flags) + # append to list + list (APPEND _flags -H -E -fno-color-diagnostics) + else() + # return as a flag string + set (_flags "-H -E -fno-color-diagnostics") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + # Windows Intel options used + # /nologo do not display compiler version information + # /QH display the include file order + # /EP preprocess to stdout, omitting #line directives + # /TC process all source or unrecognized file types as C source files + # /TP process all source or unrecognized file types as C++ source files + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH) + else() + # return as a flag string + set (_flags "${_sourceFileType${_language}} /EP /QH") + endif() + else() + # Linux / Mac OS X Intel options used + # -H print the name of each header file used + # -EP preprocess to stdout, omitting #line directives + # -Kc++ process all source or unrecognized file types as C++ source files + if (_flags) + # append to list + if ("${_language}" STREQUAL "CXX") + list (APPEND _flags -Kc++) + endif() + list (APPEND _flags -H -EP) + else() + # return as a flag string + if ("${_language}" STREQUAL "CXX") + set (_flags "-Kc++ ") + endif() + set (_flags "${_flags}-H -EP") + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) + # cl.exe options used + # /Yc creates a precompiled header file + # /Fp specifies precompiled header binary file name + # /FI forces inclusion of file + # /TC treat all files named on the command line as C source files + # /TP treat all files named on the command line as C++ source files + # /Zs syntax check only + # /Zm precompiled header memory allocation scaling factor + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" + "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + else() + # return as a flag string + set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + endif() + elseif (_compilerID MATCHES "GNU|Clang") + # GCC / Clang options used + # -x specify the source language + # -c compile but do not link + # -o place output in file + # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may + # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings) + set (_xLanguage_C "c-header") + set (_xLanguage_CXX "c++-header") + if (_flags) + # append to list + list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}") + else() + # return as a flag string + set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) + # Windows Intel options used + # /nologo do not display compiler version information + # /Yc create a precompiled header (PCH) file + # /Fp specify a path or file name for precompiled header files + # /FI tells the preprocessor to include a specified file name as the header file + # /TC process all source or unrecognized file types as C source files + # /TP process all source or unrecognized file types as C++ source files + # /Zs syntax check only + # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" + "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "/Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} /Wpch-messages") + endif() + endif() + else() + # Linux / Mac OS X Intel options used + # -pch-dir location for precompiled header files + # -pch-create name of the precompiled header (PCH) to create + # -Kc++ process all source or unrecognized file types as C++ source files + # -fsyntax-only check only for correct syntax + # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + get_filename_component(_pchDir "${_pchFile}" DIRECTORY) + get_filename_component(_pchName "${_pchFile}" NAME) + set (_xLanguage_C "c-header") + set (_xLanguage_CXX "c++-header") + if (_flags) + # append to list + if ("${_language}" STREQUAL "CXX") + list (APPEND _flags -Kc++) + endif() + list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "-Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} -Wpch-messages") + endif() + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + # cl.exe options used + # /Yu uses a precompiled header file during build + # /Fp specifies precompiled header binary file name + # /FI forces inclusion of file + # /Zm precompiled header memory allocation scaling factor + if (_pchFile) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + if (_flags) + # append to list + list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + else() + # return as a flag string + set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "/FI${_prefixFileNative}") + else() + # return as a flag string + set (_flags "/FI\"${_prefixFileNative}\"") + endif() + endif() + elseif (_compilerID MATCHES "GNU") + # GCC options used + # -include process include file as the first line of the primary source file + # -Winvalid-pch warns if precompiled header is found but cannot be used + # note: ccache requires the -include flag to be used in order to process precompiled header correctly + if (_flags) + # append to list + list (APPEND _flags "-Winvalid-pch" "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-Winvalid-pch -include \"${_prefixFile}\"") + endif() + elseif (_compilerID MATCHES "Clang") + # Clang options used + # -include process include file as the first line of the primary source file + # -include-pch include precompiled header file + # -Qunused-arguments don't emit warning for unused driver arguments + # note: ccache requires the -include flag to be used in order to process precompiled header correctly + if (_flags) + # append to list + list (APPEND _flags "-Qunused-arguments" "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-Qunused-arguments -include \"${_prefixFile}\"") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + # Windows Intel options used + # /Yu use a precompiled header (PCH) file + # /Fp specify a path or file name for precompiled header files + # /FI tells the preprocessor to include a specified file name as the header file + # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + if (_pchFile) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + if (_flags) + # append to list + list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "/Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} /Wpch-messages") + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "/FI${_prefixFileNative}") + else() + # return as a flag string + set (_flags "/FI\"${_prefixFileNative}\"") + endif() + endif() + else() + # Linux / Mac OS X Intel options used + # -pch-dir location for precompiled header files + # -pch-use name of the precompiled header (PCH) to use + # -include process include file as the first line of the primary source file + # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + if (_pchFile) + get_filename_component(_pchDir "${_pchFile}" DIRECTORY) + get_filename_component(_pchName "${_pchFile}" NAME) + if (_flags) + # append to list + list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "-Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} -Wpch-messages") + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\"") + endif() + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile) + set(_options "") + set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION LANGUAGE) + set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS COMPILER_LAUNCHER) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_LANGUAGE) + set (_option_LANGUAGE "CXX") + endif() + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + if (NOT _option_COMPILER_VERSION) + set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") + endif() + cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") + cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) + cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) + cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_pch_compilation_flags( + "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd) + if (COTIRE_VERBOSE) + message (STATUS "execute_process: ${_cmd}") + endif() + if (_option_COMPILER_ID MATCHES "MSVC") + # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared + unset (ENV{VS_UNICODE_OUTPUT}) + endif() + execute_process( + COMMAND ${_cmd} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE _result) + if (_result) + message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.") + endif() +endfunction() + +function (cotire_check_precompiled_header_support _language _target _msgVar) + set (_unsupportedCompiler + "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}") + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") + # supported since Visual Studio C++ 6.0 + # and CMake does not support an earlier version + set (${_msgVar} "" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") + # GCC PCH support requires version >= 3.4 + if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0") + set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) + else() + set (${_msgVar} "" PARENT_SCOPE) + endif() + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") + # all Clang versions have PCH support + set (${_msgVar} "" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") + # Intel PCH support requires version >= 8.0.0 + if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0") + set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) + else() + set (${_msgVar} "" PARENT_SCOPE) + endif() + else() + set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE) + endif() + get_target_property(_launcher ${_target} ${_language}_COMPILER_LAUNCHER) + if (CMAKE_${_language}_COMPILER MATCHES "ccache" OR _launcher MATCHES "ccache") + if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros|pch_defines") + set (${_msgVar} + "ccache requires the environment variable CCACHE_SLOPPINESS to be set to \"pch_defines,time_macros\"." + PARENT_SCOPE) + endif() + endif() + if (APPLE) + # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64) + cotire_get_configuration_types(_configs) + foreach (_config ${_configs}) + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags}) + list (LENGTH _architectures _numberOfArchitectures) + if (_numberOfArchitectures GREATER 1) + string (REPLACE ";" ", " _architectureStr "${_architectures}") + set (${_msgVar} + "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})." + PARENT_SCOPE) + break() + endif() + endforeach() + endif() +endfunction() + +macro (cotire_get_intermediate_dir _cotireDir) + # ${CMAKE_CFG_INTDIR} may reference a build-time variable when using a generator which supports configuration types + get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE) +endmacro() + +macro (cotire_setup_file_extension_variables) + set (_unityFileExt_C ".c") + set (_unityFileExt_CXX ".cxx") + set (_prefixFileExt_C ".h") + set (_prefixFileExt_CXX ".hxx") + set (_prefixSourceFileExt_C ".c") + set (_prefixSourceFileExt_CXX ".cxx") +endmacro() + +function (cotire_make_single_unity_source_file_path _language _target _unityFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_unityFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}") + cotire_get_intermediate_dir(_baseDir) + set (_unityFile "${_baseDir}/${_unityFileName}") + set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE) +endfunction() + +function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_unityFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + cotire_get_intermediate_dir(_baseDir) + set (_startIndex 0) + set (_index 0) + set (_unityFiles "") + set (_sourceFiles ${ARGN}) + foreach (_sourceFile ${_sourceFiles}) + get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE) + math (EXPR _unityFileCount "${_index} - ${_startIndex}") + if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes)) + if (_index GREATER 0) + # start new unity file segment + math (EXPR _endIndex "${_index} - 1") + set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") + list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") + endif() + set (_startIndex ${_index}) + endif() + math (EXPR _index "${_index} + 1") + endforeach() + list (LENGTH _sourceFiles _numberOfSources) + if (_startIndex EQUAL 0) + # there is only a single unity file + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles) + elseif (_startIndex LESS _numberOfSources) + # end with final unity file segment + math (EXPR _endIndex "${_index} - 1") + set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") + list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") + endif() + set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE) + if (COTIRE_DEBUG AND _unityFiles) + message (STATUS "unity files: ${_unityFiles}") + endif() +endfunction() + +function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_prefixFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}") + string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}") + set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE) +endfunction() + +function (cotire_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _prefixSourceFileExt_${_language}) + set (${_prefixSourceFileVar} "" PARENT_SCOPE) + return() + endif() + string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}") + set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE) +endfunction() + +function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar) + cotire_setup_file_extension_variables() + if (NOT _language) + set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}") + elseif (DEFINED _prefixFileExt_${_language}) + set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}") + else() + set (_prefixFileBaseName "") + set (_prefixFileName "") + endif() + set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE) + set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE) +endfunction() + +function (cotire_make_prefix_file_path _language _target _prefixFileVar) + cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) + set (${_prefixFileVar} "" PARENT_SCOPE) + if (_prefixFileName) + if (NOT _language) + set (_language "C") + endif() + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel|MSVC") + cotire_get_intermediate_dir(_baseDir) + set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE) + endif() + endif() +endfunction() + +function (cotire_make_pch_file_path _language _target _pchFileVar) + cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) + set (${_pchFileVar} "" PARENT_SCOPE) + if (_prefixFileBaseName AND _prefixFileName) + cotire_check_precompiled_header_support("${_language}" "${_target}" _msg) + if (NOT _msg) + if (XCODE) + # For Xcode, we completely hand off the compilation of the prefix header to the IDE + return() + endif() + cotire_get_intermediate_dir(_baseDir) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") + # MSVC uses the extension .pch added to the prefix header base name + set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") + # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended + set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") + # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended + set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") + # Intel uses the extension .pchi added to the prefix header base name + set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE) + endif() + endif() + endif() +endfunction() + +function (cotire_select_unity_source_files _unityFile _sourcesVar) + set (_sourceFiles ${ARGN}) + if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)") + set (_startIndex ${CMAKE_MATCH_1}) + set (_endIndex ${CMAKE_MATCH_2}) + list (LENGTH _sourceFiles _numberOfSources) + if (NOT _startIndex LESS _numberOfSources) + math (EXPR _startIndex "${_numberOfSources} - 1") + endif() + if (NOT _endIndex LESS _numberOfSources) + math (EXPR _endIndex "${_numberOfSources} - 1") + endif() + set (_files "") + foreach (_index RANGE ${_startIndex} ${_endIndex}) + list (GET _sourceFiles ${_index} _file) + list (APPEND _files "${_file}") + endforeach() + else() + set (_files ${_sourceFiles}) + endif() + set (${_sourcesVar} ${_files} PARENT_SCOPE) +endfunction() + +function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar) + set (_dependencySources "") + # depend on target's generated source files + get_target_property(_targetSourceFiles ${_target} SOURCES) + cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) + if (_generatedSources) + # but omit all generated source files that have the COTIRE_EXCLUDED property set to true + cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources}) + if (_excludedGeneratedSources) + list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources}) + endif() + # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly + cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources}) + if (_excludedNonDependencySources) + list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources}) + endif() + if (_generatedSources) + list (APPEND _dependencySources ${_generatedSources}) + endif() + endif() + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_language} ${_target} unity source dependencies: ${_dependencySources}") + endif() + set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) +endfunction() + +function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar) + set (_dependencySources "") + # depend on target source files marked with custom COTIRE_DEPENDENCY property + get_target_property(_targetSourceFiles ${_target} SOURCES) + cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${_targetSourceFiles}) + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_language} ${_target} prefix header dependencies: ${_dependencySources}") + endif() + set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) +endfunction() + +function (cotire_generate_target_script _language _configurations _target _targetScriptVar _targetConfigScriptVar) + set (_targetSources ${ARGN}) + cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${_targetSources}) + cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${_targetSources}) + # set up variables to be configured + set (COTIRE_TARGET_LANGUAGE "${_language}") + get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH) + cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH) + get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH) + cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH) + get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS) + get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS) + get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) + get_target_property(COTIRE_TARGET_INCLUDE_PRIORITY_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH) + cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${_targetSources}) + cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${_targetSources}) + set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}") + foreach (_config ${_configurations}) + string (TOUPPER "${_config}" _upperConfig) + cotire_get_target_include_directories( + "${_config}" "${_language}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}) + cotire_get_target_compile_definitions( + "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}) + cotire_get_target_compiler_flags( + "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}) + cotire_get_source_files_compile_definitions( + "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${_targetSources}) + endforeach() + get_target_property(COTIRE_TARGET_${_language}_COMPILER_LAUNCHER ${_target} ${_language}_COMPILER_LAUNCHER) + # set up COTIRE_TARGET_SOURCES + set (COTIRE_TARGET_SOURCES "") + foreach (_sourceFile ${_targetSources}) + get_source_file_property(_generated "${_sourceFile}" GENERATED) + if (_generated) + # use absolute paths for generated files only, retrieving the LOCATION property is an expensive operation + get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) + list (APPEND COTIRE_TARGET_SOURCES "${_sourceLocation}") + else() + list (APPEND COTIRE_TARGET_SOURCES "${_sourceFile}") + endif() + endforeach() + # copy variable definitions to cotire target script + get_cmake_property(_vars VARIABLES) + string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}") + # omit COTIRE_*_INIT variables + string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+_INIT" _initVars "${_matchVars}") + if (_initVars) + list (REMOVE_ITEM _matchVars ${_initVars}) + endif() + # omit COTIRE_VERBOSE which is passed as a CMake define on command line + list (REMOVE_ITEM _matchVars COTIRE_VERBOSE) + set (_contents "") + set (_contentsHasGeneratorExpressions FALSE) + foreach (_var IN LISTS _matchVars ITEMS + XCODE MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES + CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER_VERSION + CMAKE_${_language}_COMPILER_LAUNCHER CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1 + CMAKE_INCLUDE_FLAG_${_language} CMAKE_INCLUDE_FLAG_${_language}_SEP + CMAKE_INCLUDE_SYSTEM_FLAG_${_language} + CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG + CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG + CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) + if (DEFINED ${_var}) + string (REPLACE "\"" "\\\"" _value "${${_var}}") + set (_contents "${_contents}set (${_var} \"${_value}\")\n") + if (NOT _contentsHasGeneratorExpressions) + if ("${_value}" MATCHES "\\$<.*>") + set (_contentsHasGeneratorExpressions TRUE) + endif() + endif() + endif() + endforeach() + # generate target script file + get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) + set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}") + cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE) + if (_contentsHasGeneratorExpressions) + # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time + set (_configNameOrNoneGeneratorExpression "$<$:None>$<$>:$>") + set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}") + file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}") + else() + set (_targetCotireConfigScript "${_targetCotireScript}") + endif() + set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE) + set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE) +endfunction() + +function (cotire_setup_pch_file_compilation _language _target _targetScript _prefixFile _pchFile _hostFile) + set (_sourceFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # for Visual Studio and Intel, we attach the precompiled header compilation to the host file + # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion + if (_sourceFiles) + set (_flags "") + cotire_add_pch_compilation_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags) + set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}") + # make object file generated from host file depend on prefix header + set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") + # mark host file as cotired to prevent it from being used in another cotired target + set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}") + endif() + elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # for makefile based generator, we add a custom command to precompile the prefix header + if (_targetScript) + cotire_set_cmd_to_prologue(_cmds) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}") + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileLogPath) + else() + file (RELATIVE_PATH _pchFileLogPath "${CMAKE_BINARY_DIR}" "${_pchFile}") + endif() + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} IMPLICIT_DEPENDS ${_language} ${_prefixFile}") + endif() + set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE) + add_custom_command( + OUTPUT "${_pchFile}" + COMMAND ${_cmds} + DEPENDS "${_prefixFile}" + IMPLICIT_DEPENDS ${_language} "${_prefixFile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Building ${_language} precompiled header ${_pchFileLogPath}" + VERBATIM) + endif() + endif() +endfunction() + +function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile _hostFile) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # for Visual Studio and Intel, we include the precompiled header in all but the host file + # the host file does the precompiled header compilation, see cotire_setup_pch_file_compilation + set (_sourceFiles ${ARGN}) + list (LENGTH _sourceFiles _numberOfSourceFiles) + if (_numberOfSourceFiles GREATER 0) + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + set (_flags "") + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # make object files generated from source files depend on precompiled header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") + endif() + elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + set (_sourceFiles ${_hostFile} ${ARGN}) + if (NOT _wholeTarget) + # for makefile based generator, we force the inclusion of the prefix header for a subset + # of the source files, if this is a multi-language target or has excluded files + set (_flags "") + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + endif() + # make object files generated from source files depend on precompiled header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") + endif() +endfunction() + +function (cotire_setup_prefix_file_inclusion _language _target _prefixFile) + set (_sourceFiles ${ARGN}) + # force the inclusion of the prefix header for the given source files + set (_flags "") + set (_pchFile "") + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + # make object files generated from source files depend on prefix header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") +endfunction() + +function (cotire_get_first_set_property_value _propertyValueVar _type _object) + set (_properties ${ARGN}) + foreach (_property ${_properties}) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (_propertyValue) + set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE) + return() + endif() + endforeach() + set (${_propertyValueVar} "" PARENT_SCOPE) +endfunction() + +function (cotire_setup_combine_command _language _targetScript _joinedFile _cmdsVar) + set (_files ${ARGN}) + set (_filesPaths "") + foreach (_file ${_files}) + get_filename_component(_filePath "${_file}" ABSOLUTE) + list (APPEND _filesPaths "${_filePath}") + endforeach() + cotire_set_cmd_to_prologue(_prefixCmd) + list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine") + if (_targetScript) + list (APPEND _prefixCmd "${_targetScript}") + endif() + list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths}) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}") + endif() + set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE) + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_joinedFile}" _joinedFileLogPath) + else() + file (RELATIVE_PATH _joinedFileLogPath "${CMAKE_BINARY_DIR}" "${_joinedFile}") + endif() + get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE) + get_filename_component(_joinedFileExt "${_joinedFile}" EXT) + if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$") + set (_comment "Generating ${_language} unity source ${_joinedFileLogPath}") + elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$") + if (_joinedFileExt MATCHES "^\\.c") + set (_comment "Generating ${_language} prefix source ${_joinedFileLogPath}") + else() + set (_comment "Generating ${_language} prefix header ${_joinedFileLogPath}") + endif() + else() + set (_comment "Generating ${_joinedFileLogPath}") + endif() + add_custom_command( + OUTPUT "${_joinedFile}" + COMMAND ${_prefixCmd} + DEPENDS ${_files} + COMMENT "${_comment}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_target_pch_usage _languages _target _wholeTarget) + if (XCODE) + # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers + set (_prefixFiles "") + foreach (_language ${_languages}) + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + if (_prefixFile) + list (APPEND _prefixFiles "${_prefixFile}") + endif() + endforeach() + set (_cmds ${ARGN}) + list (LENGTH _prefixFiles _numberOfPrefixFiles) + if (_numberOfPrefixFiles GREATER 1) + # we also generate a generic, single prefix header which includes all language specific prefix headers + set (_language "") + set (_targetScript "") + cotire_make_prefix_file_path("${_language}" ${_target} _prefixHeader) + cotire_setup_combine_command("${_language}" "${_targetScript}" "${_prefixHeader}" _cmds ${_prefixFiles}) + else() + set (_prefixHeader "${_prefixFiles}") + endif() + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}") + endif() + # because CMake PRE_BUILD command does not support dependencies, + # we check dependencies explicity in cotire script mode when the pre-build action is run + add_custom_command( + TARGET "${_target}" + PRE_BUILD ${_cmds} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Updating target ${_target} prefix headers" + VERBATIM) + # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++ + set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") + set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}") + elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # for makefile based generator, we force inclusion of the prefix header for all target source files + # if this is a single-language target without any excluded files + if (_wholeTarget) + set (_language "${_languages}") + # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level + # see cotire_setup_pch_file_inclusion + if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + if (_prefixFile) + get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER) + set (_options COMPILE_OPTIONS) + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _options) + set_property(TARGET ${_target} APPEND PROPERTY ${_options}) + endif() + endif() + endif() + endif() +endfunction() + +function (cotire_setup_unity_generation_commands _language _target _targetScript _targetConfigScript _unityFiles _cmdsVar) + set (_dependencySources "") + cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN}) + foreach (_unityFile ${_unityFiles}) + set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE) + # set up compiled unity source dependencies via OBJECT_DEPENDS + # this ensures that missing source files are generated before the unity file is compiled + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}") + endif() + if (_dependencySources) + # the OBJECT_DEPENDS property requires a list of full paths + set (_objectDependsPaths "") + foreach (_sourceFile ${_dependencySources}) + get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) + list (APPEND _objectDependsPaths "${_sourceLocation}") + endforeach() + set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_objectDependsPaths}) + endif() + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel + set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj") + endif() + cotire_set_cmd_to_prologue(_unityCmd) + list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}") + if (CMAKE_VERSION VERSION_LESS "3.1.0") + set (_unityCmdDepends "${_targetScript}") + else() + # CMake 3.1.0 supports generator expressions in arguments to DEPENDS + set (_unityCmdDepends "${_targetConfigScript}") + endif() + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_unityFile}" _unityFileLogPath) + else() + file (RELATIVE_PATH _unityFileLogPath "${CMAKE_BINARY_DIR}" "${_unityFile}") + endif() + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_unityCmdDepends}") + endif() + add_custom_command( + OUTPUT "${_unityFile}" + COMMAND ${_unityCmd} + DEPENDS ${_unityCmdDepends} + COMMENT "Generating ${_language} unity source ${_unityFileLogPath}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_unityCmd}) + endforeach() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) + set (_sourceFiles ${ARGN}) + set (_dependencySources "") + cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles}) + cotire_set_cmd_to_prologue(_prefixCmd) + list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" ${_unityFiles}) + set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources}") + endif() + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileLogPath) + else() + file (RELATIVE_PATH _prefixFileLogPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") + endif() + get_filename_component(_prefixFileExt "${_prefixFile}" EXT) + if (_prefixFileExt MATCHES "^\\.c") + set (_comment "Generating ${_language} prefix source ${_prefixFileLogPath}") + else() + set (_comment "Generating ${_language} prefix header ${_prefixFileLogPath}") + endif() + # prevent pre-processing errors upon generating the prefix header when a target's generated include file does not yet exist + # we do not add a file-level dependency for the target's generated files though, because we only want to depend on their existence + # thus we make the prefix header generation depend on a custom helper target which triggers the generation of the files + set (_preTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}_pre") + if (TARGET ${_preTargetName}) + # custom helper target has already been generated while processing a different language + list (APPEND _dependencySources ${_preTargetName}) + else() + get_target_property(_targetSourceFiles ${_target} SOURCES) + cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) + if (_generatedSources) + add_custom_target("${_preTargetName}" DEPENDS ${_generatedSources}) + cotire_init_target("${_preTargetName}") + list (APPEND _dependencySources ${_preTargetName}) + endif() + endif() + add_custom_command( + OUTPUT "${_prefixFile}" "${_prefixFile}.log" + COMMAND ${_prefixCmd} + DEPENDS ${_unityFiles} ${_dependencySources} + COMMENT "${_comment}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_from_unity_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) + set (_sourceFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma + cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) + else() + set (_prefixSourceFile "${_prefixFile}") + endif() + cotire_setup_prefix_generation_command( + ${_language} ${_target} "${_targetScript}" + "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # set up generation of a prefix source file which includes the prefix header + cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) + endif() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_from_provided_command _language _target _targetScript _prefixFile _cmdsVar) + set (_prefixHeaderFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma + cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) + else() + set (_prefixSourceFile "${_prefixFile}") + endif() + cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # set up generation of a prefix source file which includes the prefix header + cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) + endif() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_init_cotire_target_properties _target) + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}") + cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}") + if (NOT _isRelative) + set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}") + endif() + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "COPY_UNITY") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET) + if (NOT _isSet) + if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}") + else() + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "") + endif() + endif() +endfunction() + +function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar) + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + string (REPLACE ";" " " _languagesStr "${_languages}") + math (EXPR _numberOfExcludedFiles "${ARGC} - 4") + if (_numberOfExcludedFiles EQUAL 0) + set (_excludedStr "") + elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4) + string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}") + else() + set (_excludedStr "excluding ${_numberOfExcludedFiles} files") + endif() + set (_targetMsg "") + if (NOT _languages) + set (_targetMsg "Target ${_target} cannot be cotired.") + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetUsePCH AND NOT _targetAddSCU) + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.") + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetUsePCH) + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.") + endif() + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetAddSCU) + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.") + endif() + else() + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired.") + endif() + endif() + set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE) +endfunction() + +function (cotire_choose_target_languages _target _targetLanguagesVar _wholeTargetVar) + set (_languages ${ARGN}) + set (_allSourceFiles "") + set (_allExcludedSourceFiles "") + set (_allCotiredSourceFiles "") + set (_targetLanguages "") + set (_pchEligibleTargetLanguages "") + get_target_property(_targetType ${_target} TYPE) + get_target_property(_targetSourceFiles ${_target} SOURCES) + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + set (_disableMsg "") + foreach (_language ${_languages}) + get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER) + get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE) + if (_prefixHeader OR _unityBuildFile) + message (STATUS "cotire: target ${_target} has already been cotired.") + set (${_targetLanguagesVar} "" PARENT_SCOPE) + return() + endif() + if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$" AND NOT "${CMAKE_${_language}_COMPILER_ID}" STREQUAL "") + cotire_check_precompiled_header_support("${_language}" "${_target}" _disableMsg) + if (_disableMsg) + set (_targetUsePCH FALSE) + endif() + endif() + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (_sourceFiles OR _excludedSources OR _cotiredSources) + list (APPEND _targetLanguages ${_language}) + endif() + if (_sourceFiles) + list (APPEND _allSourceFiles ${_sourceFiles}) + endif() + list (LENGTH _sourceFiles _numberOfSources) + if (NOT _numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + list (APPEND _pchEligibleTargetLanguages ${_language}) + endif() + if (_excludedSources) + list (APPEND _allExcludedSourceFiles ${_excludedSources}) + endif() + if (_cotiredSources) + list (APPEND _allCotiredSourceFiles ${_cotiredSources}) + endif() + endforeach() + set (_targetMsgLevel STATUS) + if (NOT _targetLanguages) + string (REPLACE ";" " or " _languagesStr "${_languages}") + set (_disableMsg "No ${_languagesStr} source files.") + set (_targetUsePCH FALSE) + set (_targetAddSCU FALSE) + endif() + if (_targetUsePCH) + if (_allCotiredSourceFiles) + cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles}) + list (REMOVE_DUPLICATES _cotireTargets) + string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}") + set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.") + set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},") + set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.") + set (_targetMsgLevel SEND_ERROR) + set (_targetUsePCH FALSE) + elseif (NOT _pchEligibleTargetLanguages) + set (_disableMsg "Too few applicable sources.") + set (_targetUsePCH FALSE) + elseif (XCODE AND _allExcludedSourceFiles) + # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target + set (_disableMsg "Exclusion of source files not supported for generator Xcode.") + set (_targetUsePCH FALSE) + elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY") + # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target + set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.") + set (_targetUsePCH FALSE) + endif() + endif() + set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH}) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU}) + cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles}) + if (_targetMsg) + if (NOT DEFINED COTIREMSG_${_target}) + set (COTIREMSG_${_target} "") + endif() + if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR + NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}") + # cache message to avoid redundant messages on re-configure + set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.") + message (${_targetMsgLevel} "${_targetMsg}") + endif() + endif() + list (LENGTH _targetLanguages _numberOfLanguages) + if (_numberOfLanguages GREATER 1 OR _allExcludedSourceFiles) + set (${_wholeTargetVar} FALSE PARENT_SCOPE) + else() + set (${_wholeTargetVar} TRUE PARENT_SCOPE) + endif() + set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE) +endfunction() + +function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar) + set (_sourceFiles ${ARGN}) + get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) + if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)") + set (_numberOfThreads "${CMAKE_MATCH_2}") + if (NOT _numberOfThreads) + # use all available cores + ProcessorCount(_numberOfThreads) + endif() + list (LENGTH _sourceFiles _numberOfSources) + math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}") + elseif (NOT _maxIncludes MATCHES "[0-9]+") + set (_maxIncludes 0) + endif() + if (COTIRE_DEBUG) + message (STATUS "${_target} unity source max includes: ${_maxIncludes}") + endif() + set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE) +endfunction() + +function (cotire_process_target_language _language _configurations _target _wholeTarget _cmdsVar) + set (${_cmdsVar} "" PARENT_SCOPE) + get_target_property(_targetSourceFiles ${_target} SOURCES) + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (NOT _sourceFiles AND NOT _cotiredSources) + return() + endif() + set (_cmds "") + # check for user provided unity source file list + get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT) + if (NOT _unitySourceFiles) + set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources}) + endif() + cotire_generate_target_script( + ${_language} "${_configurations}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles}) + # set up unity files for parallel compilation + cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles}) + cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles}) + list (LENGTH _unityFiles _numberOfUnityFiles) + if (_numberOfUnityFiles EQUAL 0) + return() + elseif (_numberOfUnityFiles GREATER 1) + cotire_setup_unity_generation_commands( + ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles}) + endif() + # set up single unity file for prefix header generation + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) + cotire_setup_unity_generation_commands( + ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFile}" _cmds ${_unitySourceFiles}) + cotire_make_prefix_file_path(${_language} ${_target} _prefixFile) + # set up prefix header + if (_prefixFile) + # check for user provided prefix header files + get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) + if (_prefixHeaderFiles) + cotire_setup_prefix_generation_from_provided_command( + ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles}) + else() + cotire_setup_prefix_generation_from_unity_command( + ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_unityFile}" _cmds ${_unitySourceFiles}) + endif() + # check if selected language has enough sources at all + list (LENGTH _sourceFiles _numberOfSources) + if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + set (_targetUsePCH FALSE) + else() + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + endif() + if (_targetUsePCH) + cotire_make_pch_file_path(${_language} ${_target} _pchFile) + if (_pchFile) + # first file in _sourceFiles is passed as the host file + cotire_setup_pch_file_compilation( + ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) + cotire_setup_pch_file_inclusion( + ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) + endif() + elseif (_prefixHeaderFiles) + # user provided prefix header must be included unconditionally + cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_sourceFiles}) + endif() + endif() + # mark target as cotired for language + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}") + if (_prefixFile) + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}") + if (_targetUsePCH AND _pchFile) + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}") + endif() + endif() + set (${_cmdsVar} ${_cmds} PARENT_SCOPE) +endfunction() + +function (cotire_setup_clean_target _target) + set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}") + if (NOT TARGET "${_cleanTargetName}") + cotire_set_cmd_to_prologue(_cmds) + get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}") + add_custom_target(${_cleanTargetName} + COMMAND ${_cmds} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Cleaning up target ${_target} cotire generated files" + VERBATIM) + cotire_init_target("${_cleanTargetName}") + endif() +endfunction() + +function (cotire_setup_pch_target _languages _configurations _target) + if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # for makefile based generators, we add a custom target to trigger the generation of the cotire related files + set (_dependsFiles "") + foreach (_language ${_languages}) + set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE) + if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # Visual Studio and Intel only create precompiled header as a side effect + list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER) + endif() + cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props}) + if (_dependsFile) + list (APPEND _dependsFiles "${_dependsFile}") + endif() + endforeach() + if (_dependsFiles) + set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}") + add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles}) + cotire_init_target("${_pchTargetName}") + cotire_add_to_pch_all_target(${_pchTargetName}) + endif() + else() + # for other generators, we add the "clean all" target to clean up the precompiled header + cotire_setup_clean_all_target() + endif() +endfunction() + +function (cotire_collect_unity_target_sources _target _languages _unityTargetSourcesVar) + get_target_property(_targetSourceFiles ${_target} SOURCES) + set (_unityTargetSources ${_targetSourceFiles}) + foreach (_language ${_languages}) + get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) + if (_unityFiles) + # remove source files that are included in the unity source + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (_sourceFiles OR _cotiredSources) + list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources}) + endif() + # add unity source files instead + list (APPEND _unityTargetSources ${_unityFiles}) + endif() + endforeach() + set (${_unityTargetSourcesVar} ${_unityTargetSources} PARENT_SCOPE) +endfunction() + +function (cotire_setup_unity_target_pch_usage _languages _target) + foreach (_language ${_languages}) + get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) + if (_unityFiles) + get_property(_userPrefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + if (_userPrefixFile AND _prefixFile) + # user provided prefix header must be included unconditionally by unity sources + cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_unityFiles}) + endif() + endif() + endforeach() +endfunction() + +function (cotire_setup_unity_build_target _languages _configurations _target) + get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) + if (NOT _unityTargetName) + set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}") + endif() + # determine unity target sub type + get_target_property(_targetType ${_target} TYPE) + if ("${_targetType}" STREQUAL "EXECUTABLE") + set (_unityTargetSubType "") + elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") + set (_unityTargetSubType "${CMAKE_MATCH_1}") + else() + message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.") + return() + endif() + # determine unity target sources + set (_unityTargetSources "") + cotire_collect_unity_target_sources(${_target} "${_languages}" _unityTargetSources) + # handle automatic Qt processing + get_target_property(_targetAutoMoc ${_target} AUTOMOC) + get_target_property(_targetAutoUic ${_target} AUTOUIC) + get_target_property(_targetAutoRcc ${_target} AUTORCC) + if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) + # if the original target sources are subject to CMake's automatic Qt processing, + # also include implicitly generated _automoc.cpp file + list (APPEND _unityTargetSources "${_target}_automoc.cpp") + set_property (SOURCE "${_target}_automoc.cpp" PROPERTY GENERATED TRUE) + endif() + # prevent AUTOMOC, AUTOUIC and AUTORCC properties from being set when the unity target is created + set (CMAKE_AUTOMOC OFF) + set (CMAKE_AUTOUIC OFF) + set (CMAKE_AUTORCC OFF) + if (COTIRE_DEBUG) + message (STATUS "add target ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}") + endif() + # generate unity target + if ("${_targetType}" STREQUAL "EXECUTABLE") + add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) + else() + add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) + endif() + if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) + # depend on the original target's implicity generated _automoc target + add_dependencies(${_unityTargetName} ${_target}_automoc) + endif() + # copy output location properties + set (_outputDirProperties + ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_ + LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_ + RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_) + if (COTIRE_UNITY_OUTPUT_DIRECTORY) + set (_setDefaultOutputDir TRUE) + if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}") + set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}") + else() + # append relative COTIRE_UNITY_OUTPUT_DIRECTORY to target's actual output directory + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) + cotire_resolve_config_properites("${_configurations}" _properties ${_outputDirProperties}) + foreach (_property ${_properties}) + get_property(_outputDir TARGET ${_target} PROPERTY ${_property}) + if (_outputDir) + get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) + set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}") + set (_setDefaultOutputDir FALSE) + endif() + endforeach() + if (_setDefaultOutputDir) + get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) + endif() + endif() + if (_setDefaultOutputDir) + set_target_properties(${_unityTargetName} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}" + LIBRARY_OUTPUT_DIRECTORY "${_outputDir}" + RUNTIME_OUTPUT_DIRECTORY "${_outputDir}") + endif() + else() + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + ${_outputDirProperties}) + endif() + # copy output name + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_ + LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_ + OUTPUT_NAME OUTPUT_NAME_ + RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_ + PREFIX _POSTFIX SUFFIX + IMPORT_PREFIX IMPORT_SUFFIX) + # copy compile stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + COMPILE_DEFINITIONS COMPILE_DEFINITIONS_ + COMPILE_FLAGS COMPILE_OPTIONS + Fortran_FORMAT Fortran_MODULE_DIRECTORY + INCLUDE_DIRECTORIES + INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_ + POSITION_INDEPENDENT_CODE + C_COMPILER_LAUNCHER CXX_COMPILER_LAUNCHER + C_INCLUDE_WHAT_YOU_USE CXX_INCLUDE_WHAT_YOU_USE + C_VISIBILITY_PRESET CXX_VISIBILITY_PRESET VISIBILITY_INLINES_HIDDEN) + # copy compile features + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED + CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED + COMPILE_FEATURES) + # copy interface stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN + COMPATIBLE_INTERFACE_STRING + INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS + INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SOURCES + INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + INTERFACE_AUTOUIC_OPTIONS NO_SYSTEM_FROM_IMPORTED) + # copy link stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH + LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED + LINK_FLAGS LINK_FLAGS_ + LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_ + LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_ + LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC + STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_ + NO_SONAME SOVERSION VERSION) + # copy cmake stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK) + # copy Apple platform specific stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + BUNDLE BUNDLE_EXTENSION FRAMEWORK FRAMEWORK_VERSION INSTALL_NAME_DIR + MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_RPATH + OSX_ARCHITECTURES OSX_ARCHITECTURES_ PRIVATE_HEADER PUBLIC_HEADER RESOURCE XCTEST + IOS_INSTALL_COMBINED) + # copy Windows platform specific stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + GNUtoMS + COMPILE_PDB_NAME COMPILE_PDB_NAME_ + COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_ + PDB_NAME PDB_NAME_ PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_ + VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION + VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE + VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK + VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION + VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER + VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION + VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES + WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS) + # copy Android platform specific stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + ANDROID_API ANDROID_API_MIN ANDROID_GUI + ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES + ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR + ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES + ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH + ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE) + # use output name from original target + get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME) + if (NOT _targetOutputName) + set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}") + endif() + # use export symbol from original target + cotire_get_target_export_symbol("${_target}" _defineSymbol) + if (_defineSymbol) + set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}") + if ("${_targetType}" STREQUAL "EXECUTABLE") + set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE) + endif() + endif() + cotire_init_target(${_unityTargetName}) + cotire_add_to_unity_all_target(${_unityTargetName}) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}") +endfunction(cotire_setup_unity_build_target) + +function (cotire_target _target) + set(_options "") + set(_oneValueArgs "") + set(_multiValueArgs LANGUAGES CONFIGURATIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_LANGUAGES) + get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + endif() + if (NOT _option_CONFIGURATIONS) + cotire_get_configuration_types(_option_CONFIGURATIONS) + endif() + # check if cotire can be applied to target at all + cotire_is_target_supported(${_target} _isSupported) + if (NOT _isSupported) + get_target_property(_imported ${_target} IMPORTED) + get_target_property(_targetType ${_target} TYPE) + if (_imported) + message (WARNING "cotire: imported ${_targetType} target ${_target} cannot be cotired.") + else() + message (STATUS "cotire: ${_targetType} target ${_target} cannot be cotired.") + endif() + return() + endif() + # resolve alias + get_target_property(_aliasName ${_target} ALIASED_TARGET) + if (_aliasName) + if (COTIRE_DEBUG) + message (STATUS "${_target} is an alias. Applying cotire to aliased target ${_aliasName} instead.") + endif() + set (_target ${_aliasName}) + endif() + # check if target needs to be cotired for build type + # when using configuration types, the test is performed at build time + cotire_init_cotire_target_properties(${_target}) + if (NOT CMAKE_CONFIGURATION_TYPES) + if (CMAKE_BUILD_TYPE) + list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index) + else() + list (FIND _option_CONFIGURATIONS "None" _index) + endif() + if (_index EQUAL -1) + if (COTIRE_DEBUG) + message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})") + endif() + return() + endif() + endif() + # when not using configuration types, immediately create cotire intermediate dir + if (NOT CMAKE_CONFIGURATION_TYPES) + cotire_get_intermediate_dir(_baseDir) + file (MAKE_DIRECTORY "${_baseDir}") + endif() + # choose languages that apply to the target + cotire_choose_target_languages("${_target}" _targetLanguages _wholeTarget ${_option_LANGUAGES}) + if (NOT _targetLanguages) + return() + endif() + set (_cmds "") + foreach (_language ${_targetLanguages}) + cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}" ${_target} ${_wholeTarget} _cmd) + if (_cmd) + list (APPEND _cmds ${_cmd}) + endif() + endforeach() + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + if (_targetAddSCU) + cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) + endif() + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + if (_targetUsePCH) + cotire_setup_target_pch_usage("${_targetLanguages}" ${_target} ${_wholeTarget} ${_cmds}) + cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) + if (_targetAddSCU) + cotire_setup_unity_target_pch_usage("${_targetLanguages}" ${_target}) + endif() + endif() + get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN) + if (_targetAddCleanTarget) + cotire_setup_clean_target(${_target}) + endif() +endfunction(cotire_target) + +function (cotire_map_libraries _strategy _mappedLibrariesVar) + set (_mappedLibraries "") + foreach (_library ${ARGN}) + if (_library MATCHES "^\\$$") + set (_libraryName "${CMAKE_MATCH_1}") + set (_linkOnly TRUE) + else() + set (_libraryName "${_library}") + set (_linkOnly FALSE) + endif() + if ("${_strategy}" MATCHES "COPY_UNITY") + cotire_is_target_supported(${_libraryName} _isSupported) + if (_isSupported) + # use target's corresponding unity target, if available + get_target_property(_libraryUnityTargetName ${_libraryName} COTIRE_UNITY_TARGET_NAME) + if (TARGET "${_libraryUnityTargetName}") + if (_linkOnly) + list (APPEND _mappedLibraries "$") + else() + list (APPEND _mappedLibraries "${_libraryUnityTargetName}") + endif() + else() + list (APPEND _mappedLibraries "${_library}") + endif() + else() + list (APPEND _mappedLibraries "${_library}") + endif() + else() + list (APPEND _mappedLibraries "${_library}") + endif() + endforeach() + list (REMOVE_DUPLICATES _mappedLibraries) + set (${_mappedLibrariesVar} ${_mappedLibraries} PARENT_SCOPE) +endfunction() + +function (cotire_target_link_libraries _target) + cotire_is_target_supported(${_target} _isSupported) + if (NOT _isSupported) + return() + endif() + get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) + if (TARGET "${_unityTargetName}") + get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} link strategy: ${_linkLibrariesStrategy}") + endif() + if ("${_linkLibrariesStrategy}" MATCHES "^(COPY|COPY_UNITY)$") + get_target_property(_linkLibraries ${_target} LINK_LIBRARIES) + if (_linkLibraries) + cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkLibraries ${_linkLibraries}) + set_target_properties(${_unityTargetName} PROPERTIES LINK_LIBRARIES "${_unityLinkLibraries}") + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} link libraries: ${_unityLinkLibraries}") + endif() + endif() + get_target_property(_interfaceLinkLibraries ${_target} INTERFACE_LINK_LIBRARIES) + if (_interfaceLinkLibraries) + cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkInterfaceLibraries ${_interfaceLinkLibraries}) + set_target_properties(${_unityTargetName} PROPERTIES INTERFACE_LINK_LIBRARIES "${_unityLinkInterfaceLibraries}") + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} interface link libraries: ${_unityLinkInterfaceLibraries}") + endif() + endif() + endif() + endif() +endfunction(cotire_target_link_libraries) + +function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName) + if (_targetName) + file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*") + else() + file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*") + endif() + # filter files in intermediate directory + set (_filesToRemove "") + foreach (_file ${_cotireFiles}) + get_filename_component(_dir "${_file}" DIRECTORY) + get_filename_component(_dirName "${_dir}" NAME) + if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}") + list (APPEND _filesToRemove "${_file}") + endif() + endforeach() + if (_filesToRemove) + if (COTIRE_VERBOSE) + message (STATUS "cleaning up ${_filesToRemove}") + endif() + file (REMOVE ${_filesToRemove}) + endif() +endfunction() + +function (cotire_init_target _targetName) + if (COTIRE_TARGETS_FOLDER) + set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}") + endif() + set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_ALL TRUE) + if (MSVC_IDE) + set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) + endif() +endfunction() + +function (cotire_add_to_pch_all_target _pchTargetName) + set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + add_custom_target("${_targetName}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + VERBATIM) + cotire_init_target("${_targetName}") + endif() + cotire_setup_clean_all_target() + add_dependencies(${_targetName} ${_pchTargetName}) +endfunction() + +function (cotire_add_to_unity_all_target _unityTargetName) + set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + add_custom_target("${_targetName}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + VERBATIM) + cotire_init_target("${_targetName}") + endif() + cotire_setup_clean_all_target() + add_dependencies(${_targetName} ${_unityTargetName}) +endfunction() + +function (cotire_setup_clean_all_target) + set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + cotire_set_cmd_to_prologue(_cmds) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}") + add_custom_target(${_targetName} + COMMAND ${_cmds} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Cleaning up all cotire generated files" + VERBATIM) + cotire_init_target("${_targetName}") + endif() +endfunction() + +function (cotire) + set(_options "") + set(_oneValueArgs "") + set(_multiValueArgs LANGUAGES CONFIGURATIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + set (_targets ${_option_UNPARSED_ARGUMENTS}) + foreach (_target ${_targets}) + if (TARGET ${_target}) + cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS}) + else() + message (WARNING "cotire: ${_target} is not a target.") + endif() + endforeach() + foreach (_target ${_targets}) + if (TARGET ${_target}) + cotire_target_link_libraries(${_target}) + endif() + endforeach() +endfunction() + +if (CMAKE_SCRIPT_MODE_FILE) + + # cotire is being run in script mode + # locate -P on command args + set (COTIRE_ARGC -1) + foreach (_index RANGE ${CMAKE_ARGC}) + if (COTIRE_ARGC GREATER -1) + set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}") + math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1") + elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P") + set (COTIRE_ARGC 0) + endif() + endforeach() + + # include target script if available + if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$") + # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES) + include("${COTIRE_ARGV2}") + endif() + + if (COTIRE_DEBUG) + message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}") + endif() + + if (NOT COTIRE_BUILD_TYPE) + set (COTIRE_BUILD_TYPE "None") + endif() + string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig) + set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}}) + set (_systemIncludeDirs ${COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}}) + set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}}) + set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}}) + # check if target has been cotired for actual build type COTIRE_BUILD_TYPE + list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index) + if (_index GREATER -1) + set (_sources ${COTIRE_TARGET_SOURCES}) + set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}}) + else() + if (COTIRE_DEBUG) + message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})") + endif() + set (_sources "") + set (_sourcesDefinitions "") + endif() + set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS}) + set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS}) + set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS}) + set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS}) + + if ("${COTIRE_ARGV1}" STREQUAL "unity") + + if (XCODE) + # executing pre-build action under Xcode, check dependency on target script + set (_dependsOption DEPENDS "${COTIRE_ARGV2}") + else() + # executing custom command, no need to re-check for dependencies + set (_dependsOption "") + endif() + + cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources}) + + cotire_generate_unity_source( + "${COTIRE_ARGV3}" ${_sources} + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions} + PRE_UNDEFS ${_targetPreUndefs} + POST_UNDEFS ${_targetPostUndefs} + SOURCES_PRE_UNDEFS ${_sourcesPreUndefs} + SOURCES_POST_UNDEFS ${_sourcesPostUndefs} + ${_dependsOption}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "prefix") + + if (XCODE) + # executing pre-build action under Xcode, check dependency on unity file and prefix dependencies + set (_dependsOption DEPENDS "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS}) + else() + # executing custom command, no need to re-check for dependencies + set (_dependsOption "") + endif() + + set (_files "") + foreach (_index RANGE 4 ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + cotire_generate_prefix_header( + "${COTIRE_ARGV3}" ${_files} + COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}" + COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" + COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} + COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" + COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}" + INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH} + IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}" + INCLUDE_PRIORITY_PATH ${COTIRE_TARGET_INCLUDE_PRIORITY_PATH} + INCLUDE_DIRECTORIES ${_includeDirs} + SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} + COMPILE_DEFINITIONS ${_compileDefinitions} + COMPILE_FLAGS ${_compileFlags} + ${_dependsOption}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "precompile") + + set (_files "") + foreach (_index RANGE 5 ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + cotire_precompile_prefix_header( + "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}" + COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}" + COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" + COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} + COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" + COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + INCLUDE_DIRECTORIES ${_includeDirs} + SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} + COMPILE_DEFINITIONS ${_compileDefinitions} + COMPILE_FLAGS ${_compileFlags}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "combine") + + if (COTIRE_TARGET_LANGUAGE) + set (_combinedFile "${COTIRE_ARGV3}") + set (_startIndex 4) + else() + set (_combinedFile "${COTIRE_ARGV2}") + set (_startIndex 3) + endif() + set (_files "") + foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + if (XCODE) + # executing pre-build action under Xcode, check dependency on files to be combined + set (_dependsOption DEPENDS ${_files}) + else() + # executing custom command, no need to re-check for dependencies + set (_dependsOption "") + endif() + + if (COTIRE_TARGET_LANGUAGE) + cotire_generate_unity_source( + "${_combinedFile}" ${_files} + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + ${_dependsOption}) + else() + cotire_generate_unity_source("${_combinedFile}" ${_files} ${_dependsOption}) + endif() + + elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup") + + cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}") + + else() + message (FATAL_ERROR "cotire: unknown command \"${COTIRE_ARGV1}\".") + endif() + +else() + + # cotire is being run in include mode + # set up all variable and property definitions + + if (NOT DEFINED COTIRE_DEBUG_INIT) + if (DEFINED COTIRE_DEBUG) + set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG}) + else() + set (COTIRE_DEBUG_INIT FALSE) + endif() + endif() + option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT}) + + if (NOT DEFINED COTIRE_VERBOSE_INIT) + if (DEFINED COTIRE_VERBOSE) + set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE}) + else() + set (COTIRE_VERBOSE_INIT FALSE) + endif() + endif() + option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT}) + + set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING + "Ignore headers with the listed file extensions from the generated prefix header.") + + set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING + "Ignore headers from these directories when generating the prefix header.") + + set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING + "Ignore sources with the listed file extensions from the generated unity source.") + + set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING + "Minimum number of sources in target required to enable use of precompiled header.") + + if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT) + if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}) + elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio") + # enable parallelization for generators that run multiple jobs by default + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j") + else() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0") + endif() + endif() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING + "Maximum number of source files to include in a single unity source file.") + + if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX) + set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix") + endif() + if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX) + set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity") + endif() + if (NOT COTIRE_INTDIR) + set (COTIRE_INTDIR "cotire") + endif() + if (NOT COTIRE_PCH_ALL_TARGET_NAME) + set (COTIRE_PCH_ALL_TARGET_NAME "all_pch") + endif() + if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME) + set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity") + endif() + if (NOT COTIRE_CLEAN_ALL_TARGET_NAME) + set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire") + endif() + if (NOT COTIRE_CLEAN_TARGET_SUFFIX) + set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire") + endif() + if (NOT COTIRE_PCH_TARGET_SUFFIX) + set (COTIRE_PCH_TARGET_SUFFIX "_pch") + endif() + if (MSVC) + # MSVC default PCH memory scaling factor of 100 percent (75 MB) is too small for template heavy C++ code + # use a bigger default factor of 170 percent (128 MB) + if (NOT DEFINED COTIRE_PCH_MEMORY_SCALING_FACTOR) + set (COTIRE_PCH_MEMORY_SCALING_FACTOR "170") + endif() + endif() + if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX) + set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity") + endif() + if (NOT DEFINED COTIRE_TARGETS_FOLDER) + set (COTIRE_TARGETS_FOLDER "cotire") + endif() + if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY) + if ("${CMAKE_GENERATOR}" MATCHES "Ninja") + # generated Ninja build files do not work if the unity target produces the same output file as the cotired target + set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity") + else() + set (COTIRE_UNITY_OUTPUT_DIRECTORY "") + endif() + endif() + + # define cotire cache variables + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH" + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "The variable can be set to a semicolon separated list of include directories." + "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." + "If not defined, defaults to empty list." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS" + BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header." + FULL_DOCS + "The variable can be set to a semicolon separated list of file extensions." + "If a header file extension matches one in the list, it will be excluded from the generated prefix header." + "Includes with an extension in CMAKE__SOURCE_FILE_EXTENSIONS are always ignored." + "If not defined, defaults to inc;inl;ipp." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS" + BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source." + FULL_DOCS + "The variable can be set to a semicolon separated list of file extensions." + "If a source file extension matches one in the list, it will be excluded from the generated unity source file." + "Source files with an extension in CMAKE__IGNORE_EXTENSIONS are always excluded." + "If not defined, defaults to m;mm." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES" + BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header." + FULL_DOCS + "The variable can be set to an integer > 0." + "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target." + "If not defined, defaults to 3." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES" + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "This may be set to an integer >= 0." + "If 0, cotire will only create a single unity source file." + "If a target contains more than that number of source files, cotire will create multiple unity source files for it." + "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores." + "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs." + "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." + "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise." + ) + + # define cotire directory properties + + define_property( + DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" + BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header." + FULL_DOCS + "See target property COTIRE_ENABLE_PRECOMPILED_HEADER." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD" + BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory." + FULL_DOCS + "See target property COTIRE_ADD_UNITY_BUILD." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_ADD_CLEAN" + BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory." + FULL_DOCS + "See target property COTIRE_ADD_CLEAN." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" + BRIEF_DOCS "Honor headers from these directories when generating the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" + BRIEF_DOCS "Header paths matching one of these directories are put at the top of the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" + BRIEF_DOCS "Define strategy for setting up the unity target's link libraries." + FULL_DOCS + "See target property COTIRE_UNITY_LINK_LIBRARIES_INIT." + ) + + # define cotire target properties + + define_property( + TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED + BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header." + FULL_DOCS + "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header." + "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target." + "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header." + "The target name will be set to this target's name with the suffix _pch appended." + "Inherited from directory." + "Defaults to TRUE." + ) + + define_property( + TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED + BRIEF_DOCS "Add a new target that performs a unity build for this target." + FULL_DOCS + "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources." + "Most of the relevant target properties will be copied from this target to the new unity build target." + "Target dependencies and linked libraries have to be manually set up for the new unity build target." + "The unity target name will be set to this target's name with the suffix _unity appended." + "Inherited from directory." + "Defaults to TRUE." + ) + + define_property( + TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED + BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target." + FULL_DOCS + "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)." + "The clean target name will be set to this target's name with the suffix _clean_cotire appended." + "Inherited from directory." + "Defaults to FALSE." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." + "Inherited from directory." + "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED + BRIEF_DOCS "Honor headers from these directories when generating the prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header." + "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH," + "the option which yields the closer relative path match wins." + "Inherited from directory." + "If not set, this property is initialized to the empty list." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" INHERITED + BRIEF_DOCS "Header paths matching one of these directories are put at the top of prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "Header file paths matching one of these directories will be inserted at the beginning of the generated prefix header." + "Header files are sorted according to the order of the directories in the property." + "If not set, this property is initialized to the empty list." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file before each target source file." + "Inherited from directory." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file after each target source file." + "Inherited from directory." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "This may be set to an integer > 0." + "If a target contains more than that number of source files, cotire will create multiple unity build files for it." + "If not set, cotire will only create a single unity source file." + "Inherited from directory." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__UNITY_SOURCE_INIT" + BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one." + FULL_DOCS + "If set, cotire will only add the given file(s) to the generated unity source file." + "If not set, cotire will add all the target source files to the generated unity source file." + "The property can be set to a user provided unity source file." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__PREFIX_HEADER_INIT" + BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one." + FULL_DOCS + "If set, cotire will add the given header file(s) to the generated prefix header file." + "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file." + "The property can be set to a user provided prefix header file (e.g., stdafx.h)." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" INHERITED + BRIEF_DOCS "Define strategy for setting up unity target's link libraries." + FULL_DOCS + "If this property is empty or set to NONE, the generated unity target's link libraries have to be set up manually." + "If this property is set to COPY, the unity target's link libraries will be copied from this target." + "If this property is set to COPY_UNITY, the unity target's link libraries will be copied from this target with considering existing unity targets." + "Inherited from directory." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__UNITY_SOURCE" + BRIEF_DOCS "Read-only property. The generated unity source file(s)." + FULL_DOCS + "cotire sets this property to the path of the generated single computation unit source file for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE__PREFIX_HEADER" + BRIEF_DOCS "Read-only property. The generated prefix header file." + FULL_DOCS + "cotire sets this property to the full path of the generated language prefix header for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE__PRECOMPILED_HEADER" + BRIEF_DOCS "Read-only property. The generated precompiled header file." + FULL_DOCS + "cotire sets this property to the full path of the generated language precompiled header binary for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME" + BRIEF_DOCS "The name of the generated unity build target corresponding to this target." + FULL_DOCS + "This property can be set to the desired name of the unity target that will be created by cotire." + "If not set, the unity target name will be set to this target's name with the suffix _unity appended." + "After this target has been processed by cotire, the property is set to the actual name of the generated unity target." + "Defaults to empty string." + ) + + # define cotire source properties + + define_property( + SOURCE PROPERTY "COTIRE_EXCLUDED" + BRIEF_DOCS "Do not modify source file's build command." + FULL_DOCS + "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header." + "The source file will also be excluded from the generated unity source file." + "Source files that have their COMPILE_FLAGS property set will be excluded by default." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_DEPENDENCY" + BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file." + FULL_DOCS + "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file." + "If the file is modified, cotire will re-generate the prefix header source upon build." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file before this file is included." + "Defaults to empty string." + ) + + define_property( + SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file after this file is included." + "Defaults to empty string." + ) + + define_property( + SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE" + BRIEF_DOCS "Start a new unity source file which includes this source file as the first one." + FULL_DOCS + "If this property is set to TRUE, cotire will complete the current unity file and start a new one." + "The new unity source file will include this source file as the first one." + "This property essentially works as a separator for unity source files." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_TARGET" + BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target." + FULL_DOCS + "cotire sets this property to the name of target, that the source file's build command has been altered for." + "Defaults to empty string." + ) + + message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.") + +endif() diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 0a106d20bd..88aa409a57 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -88,6 +88,7 @@ include (${DYNINST_ROOT}/cmake/visibility.cmake) include (${DYNINST_ROOT}/cmake/warnings.cmake) include (${DYNINST_ROOT}/cmake/options.cmake) include (${DYNINST_ROOT}/cmake/optimization.cmake) +include (${DYNINST_ROOT}/cmake/cotire.cmake) set (BUILD_SHARED_LIBS ON) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 8ea38802a5..dbb45182f8 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -120,4 +120,5 @@ endif() if(PLATFORM MATCHES nt OR PLATFORM MATCHES windows) target_link_private_libraries(common Psapi WS2_32 dbghelp) endif() +cotire(common) diff --git a/dwarf/CMakeLists.txt b/dwarf/CMakeLists.txt index 9fd218dad7..1e293b5c6b 100644 --- a/dwarf/CMakeLists.txt +++ b/dwarf/CMakeLists.txt @@ -21,4 +21,4 @@ set (SRC_LIST dyninst_library(dynDwarf dynElf common ${LIBDWARF_LIBRARIES}) - +cotire(dynDwarf) diff --git a/dynC_API/CMakeLists.txt b/dynC_API/CMakeLists.txt index 89f9e1dc2d..b900c3719a 100644 --- a/dynC_API/CMakeLists.txt +++ b/dynC_API/CMakeLists.txt @@ -11,3 +11,4 @@ set_source_files_properties(${SRC_LIST} PROPERTIES LANGUAGE CXX) add_definitions(-DDYNC_EXPORTS) dyninst_library(dynC_API dyninstAPI) +cotire(dynC_API) diff --git a/dyninstAPI/CMakeLists.txt b/dyninstAPI/CMakeLists.txt index cb634195b6..bf0c7157ae 100644 --- a/dyninstAPI/CMakeLists.txt +++ b/dyninstAPI/CMakeLists.txt @@ -201,5 +201,6 @@ if (UNIX) else() target_link_private_libraries(dyninstAPI dbghelp WS2_32 imagehlp) endif() +cotire(dyninstAPI) install(SCRIPT "${RT_BINARY_DIR}/cmake_install.cmake") diff --git a/elf/CMakeLists.txt b/elf/CMakeLists.txt index aebb5ee9af..8234c27eda 100644 --- a/elf/CMakeLists.txt +++ b/elf/CMakeLists.txt @@ -23,4 +23,4 @@ endif() dyninst_library(dynElf ${LIBELF_LIBRARIES}) add_definitions(-DDYNELF_LIB) - +cotire(dynElf) diff --git a/instructionAPI/CMakeLists.txt b/instructionAPI/CMakeLists.txt index 359ff7efa2..374553850a 100644 --- a/instructionAPI/CMakeLists.txt +++ b/instructionAPI/CMakeLists.txt @@ -38,3 +38,4 @@ dyninst_library(instructionAPI common) if(UNIX) target_link_private_libraries(instructionAPI ${Boost_LIBRARIES}) endif() +cotire(instructionAPI) diff --git a/parseAPI/CMakeLists.txt b/parseAPI/CMakeLists.txt index cb314d25dd..026c4dc930 100644 --- a/parseAPI/CMakeLists.txt +++ b/parseAPI/CMakeLists.txt @@ -144,6 +144,7 @@ endif() FILE (GLOB headers "h/*.h") FILE (GLOB dataflowheaders "../dataflowAPI/h/*.h") set_target_properties (parseAPI PROPERTIES PUBLIC_HEADER "${headers};${dataflowheaders}") +cotire(parseAPI) if(${ENABLE_STATIC_LIBS}) set_target_properties (parseAPI_static PROPERTIES PUBLIC_HEADER "${headers};${dataflowheaders}") endif() diff --git a/patchAPI/CMakeLists.txt b/patchAPI/CMakeLists.txt index 124224d0c2..8cc7145c15 100644 --- a/patchAPI/CMakeLists.txt +++ b/patchAPI/CMakeLists.txt @@ -28,4 +28,4 @@ SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX) ADD_DEFINITIONS(-DPATCHAPI_LIB) dyninst_library(patchAPI common instructionAPI parseAPI) - +cotire(patchAPI) diff --git a/proccontrol/CMakeLists.txt b/proccontrol/CMakeLists.txt index 9fda1abc42..43a51a6dfb 100644 --- a/proccontrol/CMakeLists.txt +++ b/proccontrol/CMakeLists.txt @@ -101,4 +101,5 @@ if (UNIX) target_link_private_libraries(pcontrol ${Boost_LIBRARIES}) target_link_private_libraries(pcontrol pthread) endif() +cotire(pcontrol) diff --git a/stackwalk/CMakeLists.txt b/stackwalk/CMakeLists.txt index 48cc30b6ae..a5dd20ce9c 100644 --- a/stackwalk/CMakeLists.txt +++ b/stackwalk/CMakeLists.txt @@ -108,4 +108,4 @@ endif() dyninst_library(stackwalk ${DEPS}) - +cotire(stackwalk) diff --git a/symlite/CMakeLists.txt b/symlite/CMakeLists.txt index 343ae92f86..e8878e403f 100644 --- a/symlite/CMakeLists.txt +++ b/symlite/CMakeLists.txt @@ -29,3 +29,4 @@ add_definitions(-DSYMLITE_LIB) # ARCHIVE DESTINATION ${INSTALL_LIB_DIR} # PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDE_DIR}) dyninst_library(symLite common dynElf) +cotire(symLite) diff --git a/symtabAPI/CMakeLists.txt b/symtabAPI/CMakeLists.txt index 293f32db79..2bfe8f4c8c 100644 --- a/symtabAPI/CMakeLists.txt +++ b/symtabAPI/CMakeLists.txt @@ -109,4 +109,4 @@ else() endif() dyninst_library(symtabAPI ${DEPS}) - +cotire(symtabAPI) From 483b36777c45d36df1e22e6af0eb9794d7c4b1b7 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 13 May 2016 23:58:55 -0400 Subject: [PATCH 041/180] namespace aarch64 --- common/src/arch-aarch64.C | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/src/arch-aarch64.C b/common/src/arch-aarch64.C index 7f38e68450..0043aa9b0b 100644 --- a/common/src/arch-aarch64.C +++ b/common/src/arch-aarch64.C @@ -35,13 +35,13 @@ #include "common/src/wtxKludges.h" #endif -using namespace NS_aarch64; +namespace NS_aarch64 { ATOMIC_t ATOMIC; UNCOND_BR_t UNCOND_BR; COND_BR_t COND_BR; -unsigned int NS_aarch64::swapBytesIfNeeded(unsigned int i) +unsigned int swapBytesIfNeeded(unsigned int i) { assert(0); return i; @@ -250,3 +250,5 @@ bool instruction::isAtomicStore() const { return true; return false; } + +} // namespace NS_aarch64 From b2e460f33cb2c4f652de4a415d9a0e89511945ed Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Mon, 30 May 2016 13:43:15 -0400 Subject: [PATCH 042/180] cotire vs fixes --- .gitignore | 1 + cmake/shared.cmake | 1 + cmake/warnings.cmake | 4 ++-- common/h/dyntypes.h | 2 ++ common/src/addrtranslate-win.C | 1 - common/src/ntHeaders.h | 1 - dyninstAPI_RT/src/RTwinnt.c | 2 -- instructionAPI/CMakeLists.txt | 2 +- instructionAPI/src/Instruction.C | 2 +- symtabAPI/src/Object-nt.C | 2 -- symtabAPI/src/Object-nt.h | 1 - 11 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 95999f1137..ed21f523fb 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ CMakeFiles CMakeCache.txt cmake_install.cmake */cmake_install.cmake +*/*_CXX_cotire.cmake Makefile */Makefile *.eps diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 88aa409a57..7cfb5409c4 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -106,6 +106,7 @@ foreach (p LIB INCLUDE CMAKE) endforeach() if(PLATFORM MATCHES nt OR PLATFORM MATCHES windows) + add_definitions(-DWIN32_LEAN_AND_MEAN) if (CMAKE_C_COMPILER_VERSION VERSION_GREATER 19) add_definitions(-D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS=1) else() diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake index 45497556a4..864697ccb4 100644 --- a/cmake/warnings.cmake +++ b/cmake/warnings.cmake @@ -6,6 +6,6 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual") elseif (MSVC) message(STATUS "TODO: Set up custom warning flags for MSVC") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4251 /wd4091") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251 /wd4091") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4251 /wd4091 /wd4503") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251 /wd4091 /wd4503") endif() diff --git a/common/h/dyntypes.h b/common/h/dyntypes.h index 490502c268..9ef41be62a 100644 --- a/common/h/dyntypes.h +++ b/common/h/dyntypes.h @@ -32,7 +32,9 @@ #define DYNTYPES_H #if defined(_MSC_VER) +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include #include #endif diff --git a/common/src/addrtranslate-win.C b/common/src/addrtranslate-win.C index 447bc58401..f22ff96e54 100644 --- a/common/src/addrtranslate-win.C +++ b/common/src/addrtranslate-win.C @@ -29,7 +29,6 @@ */ #include -#define WIN32_LEAN_AND_MEAN #include #include diff --git a/common/src/ntHeaders.h b/common/src/ntHeaders.h index a0a73693d4..2a2ac9e747 100644 --- a/common/src/ntHeaders.h +++ b/common/src/ntHeaders.h @@ -36,7 +36,6 @@ #pragma warning( disable : 4996 ) -#define WIN32_LEAN_AND_MEAN #include #include diff --git a/dyninstAPI_RT/src/RTwinnt.c b/dyninstAPI_RT/src/RTwinnt.c index faaddd5271..335d254b2b 100644 --- a/dyninstAPI_RT/src/RTwinnt.c +++ b/dyninstAPI_RT/src/RTwinnt.c @@ -39,7 +39,6 @@ #include #include #include -//#define WIN32_LEAN_AND_MEAN #include #include #include @@ -51,7 +50,6 @@ #include #include #include -//#include extern unsigned long dyninstTrapTableUsed; extern unsigned long dyninstTrapTableVersion; diff --git a/instructionAPI/CMakeLists.txt b/instructionAPI/CMakeLists.txt index 374553850a..b89051dcb5 100644 --- a/instructionAPI/CMakeLists.txt +++ b/instructionAPI/CMakeLists.txt @@ -26,7 +26,7 @@ SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX) # Shave 3 minute off of the time it takes to compile this file by falling back to not tracking # variables by default, rather then waiting until the variable tracking limit # is reached. -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") +if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") set_source_files_properties(src/InstructionDecoder-aarch64.C PROPERTIES COMPILE_FLAGS -fno-var-tracking-assignments) endif() diff --git a/instructionAPI/src/Instruction.C b/instructionAPI/src/Instruction.C index 20a87ca100..cd7a484704 100644 --- a/instructionAPI/src/Instruction.C +++ b/instructionAPI/src/Instruction.C @@ -28,6 +28,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define INSIDE_INSTRUCTION_API // Needs to be the first include. #include "common/src/Types.h" @@ -46,7 +47,6 @@ #include #include -#define INSIDE_INSTRUCTION_API #include "common/src/arch-x86.h" #include "version.h" diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index 2f5a4154b0..c0d6b9cf19 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -27,8 +27,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#define WIN32_LEAN_AND_MEAN #include #include diff --git a/symtabAPI/src/Object-nt.h b/symtabAPI/src/Object-nt.h index 247f1e87f7..9b85045db1 100644 --- a/symtabAPI/src/Object-nt.h +++ b/symtabAPI/src/Object-nt.h @@ -52,7 +52,6 @@ #include #include -#define WIN32_LEAN_AND_MEAN #include #include From 9af65abc621a27fb0b6d71919c5436f34039b0a0 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Mon, 30 May 2016 14:32:26 -0400 Subject: [PATCH 043/180] parallize vc++ builds --- cmake/optimization.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/optimization.cmake b/cmake/optimization.cmake index 82c6abd1d8..64a4b2d375 100644 --- a/cmake/optimization.cmake +++ b/cmake/optimization.cmake @@ -12,12 +12,12 @@ set (FORCE_FRAME_POINTER "-fno-omit-frame-pointer") # Ensure each library is fully linked set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") else (MSVC) -set (CMAKE_C_FLAGS_DEBUG "/Od /Zi /MDd /D_DEBUG") -set (CMAKE_C_FLAGS_RELEASE "/O2 /MD /D NDEBUG") -set (CMAKE_CXX_FLAGS_DEBUG "/Od /Zi /MDd /D_DEBUG") -set (CMAKE_CXX_FLAGS_RELEASE "/O2 /MD /D NDEBUG") -set (CMAKE_C_FLAGS_RELWITHDEBINFO "/O2 /Zi /MD /D NDEBUG") -set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "/O2 /Zi /MD /D NDEBUG") +set (CMAKE_C_FLAGS_DEBUG "/MP /Od /Zi /MDd /D_DEBUG") +set (CMAKE_C_FLAGS_RELEASE "/MP /O2 /MD /D NDEBUG") +set (CMAKE_CXX_FLAGS_DEBUG "/MP /Od /Zi /MDd /D_DEBUG") +set (CMAKE_CXX_FLAGS_RELEASE "/MP /O2 /MD /D NDEBUG") +set (CMAKE_C_FLAGS_RELWITHDEBINFO "/MP /O2 /Zi /MD /D NDEBUG") +set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MP /O2 /Zi /MD /D NDEBUG") set (FORCE_FRAME_POINTER "/Oy-") endif() message(STATUS "Set optimization flags") From 1814bd30468f06f85690c5995b7973539d4cb1d2 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Mon, 30 May 2016 14:44:21 -0400 Subject: [PATCH 044/180] disable unity builds --- cmake/shared.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 7cfb5409c4..67c3a9015e 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -90,6 +90,8 @@ include (${DYNINST_ROOT}/cmake/options.cmake) include (${DYNINST_ROOT}/cmake/optimization.cmake) include (${DYNINST_ROOT}/cmake/cotire.cmake) +set_directory_properties(PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) + set (BUILD_SHARED_LIBS ON) set (INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") From 161d780756f25e9e81e77e582515c8530cb50960 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Mon, 30 May 2016 17:21:23 -0400 Subject: [PATCH 045/180] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ed21f523fb..ba4db6f9db 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,4 @@ Doxyfile doxyfiles/* */*.dir/ */Debug/ +*/Release/ From d79954899a48fca66545a9c74b6aadb4ab417e3b Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Mon, 30 May 2016 17:43:06 -0400 Subject: [PATCH 046/180] limit build types --- cmake/shared.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 67c3a9015e..494973d420 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -9,6 +9,12 @@ set (SOVERSION "${DYNINST_MAJOR_VERSION}.${DYNINST_MINOR_VERSION}") set (LIBVERSION "${SOVERSION}.${DYNINST_PATCH_VERSION}") set (DYNINST_VERSION "${LIBVERSION}") +if(CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES Debug Release) + set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING + "Reset the available configurations to exclude MinSizeRel and RelWithDebugInfo" FORCE) +endif() + if (LIGHTWEIGHT_SYMTAB) set(SYMREADER symLite) else() From f9732271b871fe0a9bc8fcca4e591922356f9038 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 23 Jun 2016 13:32:55 -0400 Subject: [PATCH 047/180] build DyninstAPI_RT_static too --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62d5e5ff52..f92589fda9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ if(BUILD_RTLIB) if(MSVC) include_external_msproject(DyninstAPI_RT dyninstAPI_RT/dyninstAPI_RT.vcxproj) + include_external_msproject(DyninstAPI_RT_static dyninstAPI_RT/dyninstAPI_RT_static.vcxproj) else() add_custom_target(DyninstRT ALL From 5582e3b05cfdf0dffb3c5283cd332daa0b454084 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Thu, 23 Jun 2016 14:11:39 -0400 Subject: [PATCH 048/180] add missing include --- dyninstAPI_RT/src/RTwinnt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dyninstAPI_RT/src/RTwinnt.c b/dyninstAPI_RT/src/RTwinnt.c index 335d254b2b..39b14695df 100644 --- a/dyninstAPI_RT/src/RTwinnt.c +++ b/dyninstAPI_RT/src/RTwinnt.c @@ -35,6 +35,7 @@ #include "dyninstAPI_RT/h/dyninstAPI_RT.h" #include "RTcommon.h" #include +#include #include #include #include From 93fa7fa9f3a3e48dd26768f10a837be7c1d9f484 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Tue, 12 Jul 2016 12:49:23 -0400 Subject: [PATCH 049/180] keep 4251 disabled --- instructionAPI/h/InstructionAST.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instructionAPI/h/InstructionAST.h b/instructionAPI/h/InstructionAST.h index 4adca3eabb..6898e5a9c4 100644 --- a/instructionAPI/h/InstructionAST.h +++ b/instructionAPI/h/InstructionAST.h @@ -34,6 +34,7 @@ #if defined(_MSC_VER) // Exported class inheriting from non-exported class. This is by design; don't // use the shared_from_this externally! +#pragma warning(push) #pragma warning(disable:4251) #endif @@ -121,8 +122,7 @@ namespace Dyninst }; }; #if defined(_MSC_VER) -// reenable warning -#pragma warning(default:4251) +#pragma warning(pop) #endif From 0826a8160f7c0b562ec10b032444e8c858bf99fe Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sat, 16 Jul 2016 10:39:48 -0400 Subject: [PATCH 050/180] remove obsolete nmake config --- nmake.config | 264 --------------------------------------------------- 1 file changed, 264 deletions(-) delete mode 100644 nmake.config diff --git a/nmake.config b/nmake.config deleted file mode 100644 index cb30f1f9b9..0000000000 --- a/nmake.config +++ /dev/null @@ -1,264 +0,0 @@ -# Paradyn overall build configuration Windows/NT -# -# $Id: nmake.config,v 1.74 2006/04/13 23:05:08 legendre Exp $ -# - -#USE_VC6 = true -#USE_TCL83 = true -SUITE_NAME = Paradyn -RELEASE_NUM = 6.1 -#BUILD_MARK = - -# Apart from actual "full" releases, don't modify these build Id components. -# For personal/experimental builds, feel free to use your core/make.config.local -# file to (re-)define BUILD_MARK as you desire. - -# ***** IMPORTANT INSTALLATION/CONFIGURATION INSTRUCTIONS ***** -# Unless your site is set-up identically to that of the Paradyn/DyninstAPI -# developers, you should carefully examine the (GNU)make configuration -# parameters defined in this file, particularly utilities such as the C/C++ -# compilers, perl, flex and bison, and the installed locations and names -# for FLEX and RPCPKG. - -# most "main" modules are only two levels deep, but we need to be able to -# change this for those that are deeper in the tree -!ifndef TO_CORE -!ifdef SHELL -TO_CORE = ../.. -!else -TO_CORE = ..\.. -!endif -!endif - -!ifndef PLATFORM -PLATFORM = i386-unknown-nt4.0 -!endif - -# Destinations for library and executable installation (relative to core!) -# Warning: modification of the build/install structure is not recommended! -LIBRARY_DEST = ..\$(PLATFORM)\lib -PROGRAM_DEST = ..\$(PLATFORM)\bin - -# Usually, we look for files, binaries, libs in $(TO_CORE)/..... -# But if the file doesn't exist there (i.e. if the user hasn't checked them out -# with cvs), then we should look in a backup location. That's what this vrble -# is about. It's used several times below in this file. -BACKUP_CORE = p:\paradyn\core - -AR = ar -AS = -NASM = nasm -CC = cl -nologo -CXX = cl -nologo -LINK = link -RANLIB = -RPC_LIB = oncrpc.lib -#X11DIR = -YACC = bison -YFLAGS = -d -y -LDFLAGS = -nologo - -PERL = perl # NB: perl v5 or higher required! - -!ifdef SHELL # use richer Unix shell utilities when they're available! -CP = cp -MV = mv -RM = rm -f -MKDIR = mkdir -BUILDSTAMP = sh $(TO_CORE)/../scripts/buildstamp -win -!else # try and work as much as possible with "vanilla" WinNT! -CP = copy -MV = move -RM = del -MKDIR = md -BUILDSTAMP = cmd /c $(TO_CORE)\..\scripts\buildstamp.bat -!endif - -# COLLECTOR is only used by purify and quantify -#COLLECTOR = - -# Default module compiler; modules which want $(CC) should redefine -# this, **NOT** CC - -MODCC = $(CXX) -MODCFLAGS = $(CXXFLAGS) - -.SUFFIXES: .I .y .l - -VPATH = ..\src:$(TO_CORE)\$(LIBRARY_DEST):$(TO_CORE)\..\lib\$(PLATFORM):$(BACKUP_CORE)\..\lib\$(PLATFORM) - -IFLAGS = -I. -I$(TO_CORE) -I$(TO_CORE)\..\include - - -#don't inline -- for the files that won't emit template code -INLINE_DEFINES = - -#inline the private members of the class -- templates.o can use this -TEMP_INLINE_DEFINES = -DDO_INLINE_P="inline" - -# inline everything -- the way things should be -ALL_INLINE_DEFINES = -DDO_INLINE_F="inline" -DDO_INLINE_P="inline" - -# NO_OPT_FLAG = 1 -# if we don't want OPT_FLAG defined for a particular part of the code -# (e.g. rtinst for aix), we just need to define NO_OPT_FLAG before doing -# the include of make.config - naim -!ifndef NO_OPT_FLAG -OPT_FLAG = -Ox -!else -OPT_FLAG = -!endif - -DEFCFLAGS = -Zi -W3 -GR -EHsc -DNOMINMAX -#DEFCFLAGS used to have /wd4995, which vc6-sdk no longer likes - -CFLAGS = $(DEFCFLAGS) $(OPT_FLAG) $(IFLAGS) \ - -D_WIN32_WINNT=0x0500 # ccw 20 june 2001 was 0x0400 - -CXXFLAGS = $(DEFCFLAGS) $(OPT_FLAG) $(IFLAGS) \ - $(UNIFIED_DEF) /Zm1234 -TP -DWIN32 -D_WIN32_WINNT=0x0500 # ccw 20 june 2001 was 0x0400 #JAW-0303 /Zm1234 increases compilation memory - -# flags for kludge files, won't have warnings generated -KFLAGS = $(IFLAGS) $(UNIFIED_DEF) - -# flags for template files, don't define external template flags -# -g is optional in this case -- should be defined at module level -TFLAGS = $(IFLAGS) $(OPT_FLAG) $(TEMP_INLINE_DEFINES) $(UNIFIED_DEF) - -!ifdef DO_INLINE_ALL -CXXFLAGS = $(CXXFLAGS) -DDO_INLINE_F="inline" -DDO_INLINE_P="inline" -!endif - -# Start off LIBDIR to point to the user's devel area's paradyn lib directory. -# As a backup, in case the user hasn't checked out and compiled some paradyn lib, -# we stick in /p/paradyn/lib _second_. -LIBDIR = -LIBPATH:$(TO_CORE)\$(LIBRARY_DEST) \ - -LIBPATH:$(TO_CORE)\..\$(PLATFORM)\lib \ - -LIBPATH:$(TO_CORE)\..\lib\$(PLATFORM) \ - -LIBPATH:$(BACKUP_CORE)\..\$(PLATFORM)\lib \ - -LIBPATH:$(BACKUP_CORE)\..\lib\$(PLATFORM) \ - -LIBPATH:$(RPCPKG_LIB) - -# Set IGEN to point to $(TO_CORE)/../bin/$(PLATFORM)/igen, if it exists, -# else set it to $(BACKUP_CORE)/../bin/$(PLATFORM)/igen, if it exists, -# else set it to just "igen" (i.e. assume it's in the user's path) -IGEN = $(TO_CORE)\igen\$(PLATFORM) - -!ifdef NO_IMPLICIT_TEMPLATES -#CFLAGS += -fno-implicit-templates -#CXXFLAGS += -fno-implicit-templates -#KFLAGS += -fno-implicit-templates -#TFLAGS += -fno-implicit-templates -!endif - -!ifndef INSTANTIATE_TEMPLATES -!ifndef NO_IMPLICIT_TEMPLATES -# -fexternal-templates and -Dexternal_templates should both be used or -# neither should be used; add them to CFLAGS, CXXFLAGS, and KFLAGS -# (but not to TFLAGS). -# -#CFLAGS = $(CFLAGS) -fexternal-templates -Dexternal_templates -#CXXFLAGS = $(CXXFLAGS) -fexternal-templates -Dexternal_templates -#KFLAGS = $(KFLAGS) -fexternal-templates -Dexternal_templates -!endif -!endif - -# Include any per-user configuration changes; this "local" config file -# should *not* be under CVS control, so that it never gets committed. - -!if exist ($(TO_CORE)\nmake.config.local) -!include $(TO_CORE)\nmake.config.local -!endif - -# Set variables to default values if they weren't set in -# nmake.config.local - -!ifdef USES_TCLTK - -!ifndef TCLTK_DIR -!ifdef USE_TCL83 -TCLTK_DIR = p:\paradyn\packages\tcl8.3.4 -!else -TCLTK_DIR = p:\paradyn\packages\tcl8.4.5 -!endif -!endif - -!ifndef TCLTK_LIB_DIR -TCLTK_LIB_DIR = $(TCLTK_DIR)\lib -!endif - -!ifndef TCLTK_INC_DIR -TCLTK_INC_DIR = $(TCLTK_DIR)\include -!endif -!endif - -!ifdef USES_FLEX -!ifndef FLEX_DIR -FLEX_DIR = c:\cygwin\lib -!endif -!endif - -!ifndef RPCPKG -RPCPKG = p:\paradyn\packages\winnt\oncrpc -!endif -!ifndef RPCPKG_INC -RPCPKG_INC = $(RPCPKG) -!endif -!ifndef RPCPKG_LIB -RPCPKG_LIB = $(RPCPKG)\lib -!endif - -!ifndef NASM -NASM = P:\paradyn\packages\nasm\bin\nasmw -!endif - -# ***** EXTERNAL SOFTWARE CONFIGURATION ***** - -!ifdef USES_TCLTK -# TCL2C is used to generate compilable sources from tcl files -# Note this needs to be back slashes - -!ifdef SHELL -TCL2C = $(TO_CORE)/../scripts/tcl2c -!else -TCL2C = $(TO_CORE)\..\scripts\tcl2c -!endif -TCL2C_GEN_SRCS = tcl2c.C - -# Specify the Tcl/Tk files to be used -!ifndef USE_TCL83 - -TCLTK_LIBVER_ID = 84t -CFLAGS = $(CFLAGS) -DTCLCONST="const" -CXXFLAGS = $(CXXFLAGS) -DTCLCONST="const" -TFLAGS = $(TFLAGS) -DTCLCONST="const" -KFLAGS = $(KFLAGS) -DTCLCONST="const" - -!else - -TCLTK_LIBVER_ID = 83 -CFLAGS = $(CFLAGS) -DTCLCONST="" -CXXFLAGS = $(CXXFLAGS) -DTCLCONST="" -TFLAGS = $(TFLAGS) -DTCLCONST="" -KFLAGS = $(KFLAGS) -DTCLCONST="" - -!endif - -TCLTK_INCLUDES = -I$(TCLTK_INC_DIR) -TCLTK_LIBPATH = -LIBPATH:$(TCLTK_LIB_DIR) -TCL_LIB = tcl$(TCLTK_LIBVER_ID).lib -TK_LIB = tk$(TCLTK_LIBVER_ID).lib -TCLTK_LIBS = $(TCL_LIB) $(TK_LIB) - -IFLAGS = $(IFLAGS) $(TCLTK_INCLUDES) -LIBDIR = $(LIBDIR) $(TCLTK_LIBPATH) -!endif /* USES_TCLTK */ - -!ifdef USES_FLEX -LEX = flex -FLEX_LIB = libfl.a -LDFLAGS = $(LDFLAGS) -LIBPATH:$(FLEX_DIR) -!endif - -IFLAGS = $(IFLAGS) -I$(RPCPKG_INC) -LIBDIR = $(LIBDIR) -LIBPATH:$(RPCPKG_LIB) From 7c90ebb86f374ae8c5def914136d5cba9a00f2b4 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 23 Aug 2016 16:09:45 -0500 Subject: [PATCH 051/180] Added generated cotire directories to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ba4db6f9db..af40c844e6 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,4 @@ doxyfiles/* */*.dir/ */Debug/ */Release/ +cotire/ From 9726d0336d195440d62199a847d3568c9e0ac68c Mon Sep 17 00:00:00 2001 From: John Detter Date: Fri, 26 Aug 2016 12:41:58 -0500 Subject: [PATCH 052/180] Fixes make install issue --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5702047603..e720a4d97b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ endif() if(BUILD_RTLIB) # Build the RT library as a separate project so we can change compilers message(STATUS "Configuring DyninstAPI_RT") - file(REMOVE_RECURSE ${RT_BINARY_DIR}/CMakeCache.txt ${RT_BINARY_DIR}/Makefile) + file(REMOVE_RECURSE ${RT_BINARY_DIR}/CMakeCache.txt ${RT_BINARY_DIR}/CMakeFiles ${RT_BINARY_DIR}/Makefile) file(MAKE_DIRECTORY ${RT_BINARY_DIR}) if (PLATFORM MATCHES bgq) set (RT_C_COMPILER mpicc CACHE STRING "Compiler for runtime library") From e87877a5b1d09e0883c88ee620a2b1afec954b88 Mon Sep 17 00:00:00 2001 From: John Detter Date: Fri, 26 Aug 2016 14:57:32 -0500 Subject: [PATCH 053/180] Replaced nullptr with NULL (RHEL6 GCC 4.4 compatibility) --- instructionAPI/src/BinaryFunction.C | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/instructionAPI/src/BinaryFunction.C b/instructionAPI/src/BinaryFunction.C index 18c7762172..4736776272 100644 --- a/instructionAPI/src/BinaryFunction.C +++ b/instructionAPI/src/BinaryFunction.C @@ -413,43 +413,43 @@ namespace Dyninst bool BinaryFunction::isAdd() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } bool BinaryFunction::isMultiply() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } bool BinaryFunction::isLeftShift() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } bool BinaryFunction::isRightArithmeticShift() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } bool BinaryFunction::isAndResult() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } bool BinaryFunction::isOrResult() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } bool BinaryFunction::isRightLogicalShift() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } bool BinaryFunction::isRightRotate() const { - return dynamic_cast(m_funcPtr.get()) != nullptr; + return dynamic_cast(m_funcPtr.get()) != NULL; } }; }; From a032945f8f2b090ca63a5984123797695b916151 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 26 Aug 2016 17:19:32 -0700 Subject: [PATCH 054/180] instructionAPI: use uintmax_t when formatting addresses --- instructionAPI/src/Operand.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instructionAPI/src/Operand.C b/instructionAPI/src/Operand.C index 8ccf5eee3f..0b1bc41dfd 100644 --- a/instructionAPI/src/Operand.C +++ b/instructionAPI/src/Operand.C @@ -120,7 +120,7 @@ namespace Dyninst Result res = op_value->eval(); if (res.defined) { stringstream ret; - ret << hex << res.convert() << dec; + ret << hex << res.convert() << dec; return ret.str(); } } From 77c0196ed4cc2ddeabb43e5c5ba7b484126aa303 Mon Sep 17 00:00:00 2001 From: John Detter Date: Mon, 29 Aug 2016 09:53:30 -0500 Subject: [PATCH 055/180] Had to disable precompiled headers for instructionAPI. --- instructionAPI/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/instructionAPI/CMakeLists.txt b/instructionAPI/CMakeLists.txt index b89051dcb5..4709fb41cc 100644 --- a/instructionAPI/CMakeLists.txt +++ b/instructionAPI/CMakeLists.txt @@ -38,4 +38,6 @@ dyninst_library(instructionAPI common) if(UNIX) target_link_private_libraries(instructionAPI ${Boost_LIBRARIES}) endif() + +set_target_properties(instructionAPI PROPERTIES COTIRE_ENABLE_PRECOMPILED_HEADER FALSE) cotire(instructionAPI) From 4ca18d9e66dd8f9ffd12ac8fcd3386127db8d182 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 26 Aug 2016 17:42:54 -0700 Subject: [PATCH 056/180] fix insnCodeGen::modifyData's 64-bit conversion On RHEL6 with a prelinked `/lib64/libc-2.12.so`, all of tests involving fork instrumentation were getting SIGSEGV in the mutatee. This worked in 9.1, and it also works fine after `prelink -u` to undo libc. Using git-bisect found 2b86eb4577bb as the point of regression. It seems prelink ends up with libc sitting far away from the relocation buffer, more than a 32-bit displacement, so `insnCodeGen::modifyData` decides to rewrite that to a 64-bit immediate. To do this, it has to emit additional instructions first. But after the commit above, part of the rewritten instruction has already been written when we're trying to emit those extras, and things gets clobbered. This patch emits those preamble instructions first, before any part of the newly rewritten instruction is copied out. --- dyninstAPI/src/codegen-x86.C | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dyninstAPI/src/codegen-x86.C b/dyninstAPI/src/codegen-x86.C index ef8a6b0b47..ad9ac8ec90 100644 --- a/dyninstAPI/src/codegen-x86.C +++ b/dyninstAPI/src/codegen-x86.C @@ -1196,10 +1196,6 @@ bool insnCodeGen::modifyData(Address targetAddr, instruction &insn, codeGen &gen /* get the prefix count */ size_t pref_count = instruct.getSize(); - - /* copy the prefix */ - memcpy(newInsn, origInsn, pref_count); - newInsn += pref_count; origInsn += pref_count; /* Decode the opcode */ @@ -1208,27 +1204,31 @@ bool insnCodeGen::modifyData(Address targetAddr, instruction &insn, codeGen &gen /* Calculate the amount of opcode bytes */ size_t opcode_len = instruct.getSize() - pref_count; - - /* Copy the opcode bytes */ - memcpy(newInsn, origInsn, opcode_len); - newInsn += opcode_len; origInsn += opcode_len; /* Get the value of the Mod/RM byte */ - unsigned char mod_rm = *origInsn; - origInsn++; + unsigned char mod_rm = *origInsn++; +#if defined(arch_x86_64) if (!is_disp32(newDisp+insnSz) && !is_addr32(targetAddr)) { // Case C: replace with 64-bit. + // This preamble must come before any writes to newInsn! is_data_abs64 = true; -#if defined(arch_x86_64) pointer_reg = (mod_rm & 0x38) != 0 ? 0 : 3; SET_PTR(newInsn, gen); emitPushReg64(pointer_reg, gen); emitMovImmToReg64(pointer_reg, targetAddr, true, gen); REGET_PTR(newInsn, gen); + } +#endif + + /* copy the prefix and opcode bytes */ + memcpy(newInsn, origInsnStart, pref_count + opcode_len); + newInsn += pref_count + opcode_len; + if (is_data_abs64) + { // change ModRM byte to use [pointer_reg]: requires // us to change last three bits (the r/m field) // to the value of pointer_reg @@ -1236,7 +1236,6 @@ bool insnCodeGen::modifyData(Address targetAddr, instruction &insn, codeGen &gen mod_rm = (mod_rm & 0xf8) | pointer_reg; /* Set the new ModR/M byte of the new instruction */ *newInsn++ = mod_rm; -#endif } else if (is_disp32(newDisp + insnSz)) { /* Instruction can remain a 32 bit instruction */ From 79dc72a920874aabdc275923ccdccdd7a00df78b Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 30 Aug 2016 16:52:44 -0500 Subject: [PATCH 057/180] Check GCC version and decide whether or not to use cotire --- CMakeLists.txt | 10 ++++++++++ cmake/shared.cmake | 5 ++++- common/CMakeLists.txt | 5 ++++- dwarf/CMakeLists.txt | 4 +++- dynC_API/CMakeLists.txt | 4 +++- dyninstAPI/CMakeLists.txt | 4 +++- elf/CMakeLists.txt | 4 +++- instructionAPI/CMakeLists.txt | 5 +++-- parseAPI/CMakeLists.txt | 4 +++- patchAPI/CMakeLists.txt | 4 +++- proccontrol/CMakeLists.txt | 4 +++- stackwalk/CMakeLists.txt | 4 +++- symlite/CMakeLists.txt | 4 +++- symtabAPI/CMakeLists.txt | 5 ++++- 14 files changed, 52 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e720a4d97b..6721487cf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,16 @@ ENDIF() set(RT_SOURCE_DIR ${DYNINST_ROOT}/dyninstAPI_RT) set(RT_BINARY_DIR ${PROJECT_BINARY_DIR}/dyninstAPI_RT) +# Check for cotire-gcc compatibility +set(USE_COTIRE true) +IF(CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) + IF(GCC_VERSION VERSION_LESS 4.5) + SET(USE_COTIRE false) + ENDIF() +ENDIF(CMAKE_COMPILER_IS_GNUCC) + include (${DYNINST_ROOT}/cmake/shared.cmake) configure_file(cmake/version.h.in common/h/version.h) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 494973d420..5dca70deba 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -94,7 +94,10 @@ include (${DYNINST_ROOT}/cmake/visibility.cmake) include (${DYNINST_ROOT}/cmake/warnings.cmake) include (${DYNINST_ROOT}/cmake/options.cmake) include (${DYNINST_ROOT}/cmake/optimization.cmake) -include (${DYNINST_ROOT}/cmake/cotire.cmake) + +if (USE_COTIRE EQUAL true) + include (${DYNINST_ROOT}/cmake/cotire.cmake) +endif() set_directory_properties(PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index dbb45182f8..32576ae049 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -120,5 +120,8 @@ endif() if(PLATFORM MATCHES nt OR PLATFORM MATCHES windows) target_link_private_libraries(common Psapi WS2_32 dbghelp) endif() -cotire(common) + +IF (USE_COTIRE EQUAL true) + cotire(common) +ENDIF() diff --git a/dwarf/CMakeLists.txt b/dwarf/CMakeLists.txt index 1e293b5c6b..69f57107a5 100644 --- a/dwarf/CMakeLists.txt +++ b/dwarf/CMakeLists.txt @@ -21,4 +21,6 @@ set (SRC_LIST dyninst_library(dynDwarf dynElf common ${LIBDWARF_LIBRARIES}) -cotire(dynDwarf) +if (USE_COTIRE EQUAL true) + cotire(dynDwarf) +endif() diff --git a/dynC_API/CMakeLists.txt b/dynC_API/CMakeLists.txt index b900c3719a..4758d35f47 100644 --- a/dynC_API/CMakeLists.txt +++ b/dynC_API/CMakeLists.txt @@ -11,4 +11,6 @@ set_source_files_properties(${SRC_LIST} PROPERTIES LANGUAGE CXX) add_definitions(-DDYNC_EXPORTS) dyninst_library(dynC_API dyninstAPI) -cotire(dynC_API) +if (USE_COTIRE EQUAL true) + cotire(dynC_API) +endif() diff --git a/dyninstAPI/CMakeLists.txt b/dyninstAPI/CMakeLists.txt index bf0c7157ae..6f951f06b5 100644 --- a/dyninstAPI/CMakeLists.txt +++ b/dyninstAPI/CMakeLists.txt @@ -201,6 +201,8 @@ if (UNIX) else() target_link_private_libraries(dyninstAPI dbghelp WS2_32 imagehlp) endif() -cotire(dyninstAPI) +if (USE_COTIRE EQUAL true) + cotire(dyninstAPI) +endif() install(SCRIPT "${RT_BINARY_DIR}/cmake_install.cmake") diff --git a/elf/CMakeLists.txt b/elf/CMakeLists.txt index 8234c27eda..8e6a0de927 100644 --- a/elf/CMakeLists.txt +++ b/elf/CMakeLists.txt @@ -23,4 +23,6 @@ endif() dyninst_library(dynElf ${LIBELF_LIBRARIES}) add_definitions(-DDYNELF_LIB) -cotire(dynElf) +if (USE_COTIRE EQUAL true) + cotire(dynElf) +endif() diff --git a/instructionAPI/CMakeLists.txt b/instructionAPI/CMakeLists.txt index 4709fb41cc..08320bda46 100644 --- a/instructionAPI/CMakeLists.txt +++ b/instructionAPI/CMakeLists.txt @@ -39,5 +39,6 @@ if(UNIX) target_link_private_libraries(instructionAPI ${Boost_LIBRARIES}) endif() -set_target_properties(instructionAPI PROPERTIES COTIRE_ENABLE_PRECOMPILED_HEADER FALSE) -cotire(instructionAPI) +if (USE_COTIRE EQUAL true) + cotire(instructionAPI) +endif() diff --git a/parseAPI/CMakeLists.txt b/parseAPI/CMakeLists.txt index 026c4dc930..34f3327601 100644 --- a/parseAPI/CMakeLists.txt +++ b/parseAPI/CMakeLists.txt @@ -144,7 +144,9 @@ endif() FILE (GLOB headers "h/*.h") FILE (GLOB dataflowheaders "../dataflowAPI/h/*.h") set_target_properties (parseAPI PROPERTIES PUBLIC_HEADER "${headers};${dataflowheaders}") -cotire(parseAPI) +if (USE_COTIRE EQUAL true) + cotire(parseAPI) +endif() if(${ENABLE_STATIC_LIBS}) set_target_properties (parseAPI_static PROPERTIES PUBLIC_HEADER "${headers};${dataflowheaders}") endif() diff --git a/patchAPI/CMakeLists.txt b/patchAPI/CMakeLists.txt index 8cc7145c15..bef59a2207 100644 --- a/patchAPI/CMakeLists.txt +++ b/patchAPI/CMakeLists.txt @@ -28,4 +28,6 @@ SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX) ADD_DEFINITIONS(-DPATCHAPI_LIB) dyninst_library(patchAPI common instructionAPI parseAPI) -cotire(patchAPI) +if (USE_COTIRE EQUAL true) + cotire(patchAPI) +endif() diff --git a/proccontrol/CMakeLists.txt b/proccontrol/CMakeLists.txt index 43a51a6dfb..07a8d709ab 100644 --- a/proccontrol/CMakeLists.txt +++ b/proccontrol/CMakeLists.txt @@ -101,5 +101,7 @@ if (UNIX) target_link_private_libraries(pcontrol ${Boost_LIBRARIES}) target_link_private_libraries(pcontrol pthread) endif() -cotire(pcontrol) +if (USE_COTIRE EQUAL true) + cotire(pcontrol) +endif() diff --git a/stackwalk/CMakeLists.txt b/stackwalk/CMakeLists.txt index a5dd20ce9c..3719bbd055 100644 --- a/stackwalk/CMakeLists.txt +++ b/stackwalk/CMakeLists.txt @@ -108,4 +108,6 @@ endif() dyninst_library(stackwalk ${DEPS}) -cotire(stackwalk) +if (USE_COTIRE EQUAL true) + cotire(stackwalk) +endif() diff --git a/symlite/CMakeLists.txt b/symlite/CMakeLists.txt index e8878e403f..1836efbc4e 100644 --- a/symlite/CMakeLists.txt +++ b/symlite/CMakeLists.txt @@ -29,4 +29,6 @@ add_definitions(-DSYMLITE_LIB) # ARCHIVE DESTINATION ${INSTALL_LIB_DIR} # PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDE_DIR}) dyninst_library(symLite common dynElf) -cotire(symLite) +if (USE_COTIRE EQUAL true) + cotire(symLite) +endif() diff --git a/symtabAPI/CMakeLists.txt b/symtabAPI/CMakeLists.txt index 2bfe8f4c8c..9db8dde8e4 100644 --- a/symtabAPI/CMakeLists.txt +++ b/symtabAPI/CMakeLists.txt @@ -109,4 +109,7 @@ else() endif() dyninst_library(symtabAPI ${DEPS}) -cotire(symtabAPI) + +if (USE_COTIRE EQUAL true) + cotire(symtabAPI) +endif() From 11b63284da8b425cee5b3c1a87464d3606f8d612 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 30 Aug 2016 17:19:37 -0500 Subject: [PATCH 058/180] Check cmake version to make sure cotire is supported --- CMakeLists.txt | 5 +++++ cmake/shared.cmake | 2 +- common/CMakeLists.txt | 2 +- dwarf/CMakeLists.txt | 2 +- dynC_API/CMakeLists.txt | 2 +- dyninstAPI/CMakeLists.txt | 2 +- elf/CMakeLists.txt | 2 +- instructionAPI/CMakeLists.txt | 2 +- parseAPI/CMakeLists.txt | 2 +- patchAPI/CMakeLists.txt | 2 +- proccontrol/CMakeLists.txt | 2 +- stackwalk/CMakeLists.txt | 2 +- symlite/CMakeLists.txt | 2 +- symtabAPI/CMakeLists.txt | 2 +- 14 files changed, 18 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6721487cf8..c4828c081f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,11 @@ IF(CMAKE_COMPILER_IS_GNUCC) ENDIF() ENDIF(CMAKE_COMPILER_IS_GNUCC) +# Make sure our CMake version is actually supported by cotire +IF(CMAKE_VERSION VERSION_LESS 2.8.12) + SET(USE_COTIRE false) +ENDIF() + include (${DYNINST_ROOT}/cmake/shared.cmake) configure_file(cmake/version.h.in common/h/version.h) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 5dca70deba..dcaa85cc3f 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -95,7 +95,7 @@ include (${DYNINST_ROOT}/cmake/warnings.cmake) include (${DYNINST_ROOT}/cmake/options.cmake) include (${DYNINST_ROOT}/cmake/optimization.cmake) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) include (${DYNINST_ROOT}/cmake/cotire.cmake) endif() diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 32576ae049..7c83397cc5 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -121,7 +121,7 @@ if(PLATFORM MATCHES nt OR PLATFORM MATCHES windows) target_link_private_libraries(common Psapi WS2_32 dbghelp) endif() -IF (USE_COTIRE EQUAL true) +IF (USE_COTIRE) cotire(common) ENDIF() diff --git a/dwarf/CMakeLists.txt b/dwarf/CMakeLists.txt index 69f57107a5..9e3295ac63 100644 --- a/dwarf/CMakeLists.txt +++ b/dwarf/CMakeLists.txt @@ -21,6 +21,6 @@ set (SRC_LIST dyninst_library(dynDwarf dynElf common ${LIBDWARF_LIBRARIES}) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(dynDwarf) endif() diff --git a/dynC_API/CMakeLists.txt b/dynC_API/CMakeLists.txt index 4758d35f47..2e90d3a1a8 100644 --- a/dynC_API/CMakeLists.txt +++ b/dynC_API/CMakeLists.txt @@ -11,6 +11,6 @@ set_source_files_properties(${SRC_LIST} PROPERTIES LANGUAGE CXX) add_definitions(-DDYNC_EXPORTS) dyninst_library(dynC_API dyninstAPI) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(dynC_API) endif() diff --git a/dyninstAPI/CMakeLists.txt b/dyninstAPI/CMakeLists.txt index 6f951f06b5..43f67ae95d 100644 --- a/dyninstAPI/CMakeLists.txt +++ b/dyninstAPI/CMakeLists.txt @@ -201,7 +201,7 @@ if (UNIX) else() target_link_private_libraries(dyninstAPI dbghelp WS2_32 imagehlp) endif() -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(dyninstAPI) endif() diff --git a/elf/CMakeLists.txt b/elf/CMakeLists.txt index 8e6a0de927..9950c9936e 100644 --- a/elf/CMakeLists.txt +++ b/elf/CMakeLists.txt @@ -23,6 +23,6 @@ endif() dyninst_library(dynElf ${LIBELF_LIBRARIES}) add_definitions(-DDYNELF_LIB) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(dynElf) endif() diff --git a/instructionAPI/CMakeLists.txt b/instructionAPI/CMakeLists.txt index 08320bda46..4e8edb273c 100644 --- a/instructionAPI/CMakeLists.txt +++ b/instructionAPI/CMakeLists.txt @@ -39,6 +39,6 @@ if(UNIX) target_link_private_libraries(instructionAPI ${Boost_LIBRARIES}) endif() -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(instructionAPI) endif() diff --git a/parseAPI/CMakeLists.txt b/parseAPI/CMakeLists.txt index 34f3327601..45cfa9aadc 100644 --- a/parseAPI/CMakeLists.txt +++ b/parseAPI/CMakeLists.txt @@ -144,7 +144,7 @@ endif() FILE (GLOB headers "h/*.h") FILE (GLOB dataflowheaders "../dataflowAPI/h/*.h") set_target_properties (parseAPI PROPERTIES PUBLIC_HEADER "${headers};${dataflowheaders}") -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(parseAPI) endif() if(${ENABLE_STATIC_LIBS}) diff --git a/patchAPI/CMakeLists.txt b/patchAPI/CMakeLists.txt index bef59a2207..ef386acc88 100644 --- a/patchAPI/CMakeLists.txt +++ b/patchAPI/CMakeLists.txt @@ -28,6 +28,6 @@ SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX) ADD_DEFINITIONS(-DPATCHAPI_LIB) dyninst_library(patchAPI common instructionAPI parseAPI) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(patchAPI) endif() diff --git a/proccontrol/CMakeLists.txt b/proccontrol/CMakeLists.txt index 07a8d709ab..5e072beb04 100644 --- a/proccontrol/CMakeLists.txt +++ b/proccontrol/CMakeLists.txt @@ -101,7 +101,7 @@ if (UNIX) target_link_private_libraries(pcontrol ${Boost_LIBRARIES}) target_link_private_libraries(pcontrol pthread) endif() -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(pcontrol) endif() diff --git a/stackwalk/CMakeLists.txt b/stackwalk/CMakeLists.txt index 3719bbd055..48cacbd867 100644 --- a/stackwalk/CMakeLists.txt +++ b/stackwalk/CMakeLists.txt @@ -108,6 +108,6 @@ endif() dyninst_library(stackwalk ${DEPS}) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(stackwalk) endif() diff --git a/symlite/CMakeLists.txt b/symlite/CMakeLists.txt index 1836efbc4e..6f1ef3de13 100644 --- a/symlite/CMakeLists.txt +++ b/symlite/CMakeLists.txt @@ -29,6 +29,6 @@ add_definitions(-DSYMLITE_LIB) # ARCHIVE DESTINATION ${INSTALL_LIB_DIR} # PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDE_DIR}) dyninst_library(symLite common dynElf) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(symLite) endif() diff --git a/symtabAPI/CMakeLists.txt b/symtabAPI/CMakeLists.txt index 9db8dde8e4..88bde95b02 100644 --- a/symtabAPI/CMakeLists.txt +++ b/symtabAPI/CMakeLists.txt @@ -110,6 +110,6 @@ endif() dyninst_library(symtabAPI ${DEPS}) -if (USE_COTIRE EQUAL true) +if (USE_COTIRE) cotire(symtabAPI) endif() From 7c121d47379bdbe910c750d60c4933b95b7a5f1a Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 30 Aug 2016 17:22:16 -0500 Subject: [PATCH 059/180] Moved cotire logic to shared.cmake --- CMakeLists.txt | 15 --------------- cmake/shared.cmake | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c4828c081f..e720a4d97b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,21 +14,6 @@ ENDIF() set(RT_SOURCE_DIR ${DYNINST_ROOT}/dyninstAPI_RT) set(RT_BINARY_DIR ${PROJECT_BINARY_DIR}/dyninstAPI_RT) -# Check for cotire-gcc compatibility -set(USE_COTIRE true) -IF(CMAKE_COMPILER_IS_GNUCC) - execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) - IF(GCC_VERSION VERSION_LESS 4.5) - SET(USE_COTIRE false) - ENDIF() -ENDIF(CMAKE_COMPILER_IS_GNUCC) - -# Make sure our CMake version is actually supported by cotire -IF(CMAKE_VERSION VERSION_LESS 2.8.12) - SET(USE_COTIRE false) -ENDIF() - include (${DYNINST_ROOT}/cmake/shared.cmake) configure_file(cmake/version.h.in common/h/version.h) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index dcaa85cc3f..01c803876b 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -95,6 +95,21 @@ include (${DYNINST_ROOT}/cmake/warnings.cmake) include (${DYNINST_ROOT}/cmake/options.cmake) include (${DYNINST_ROOT}/cmake/optimization.cmake) +# Check for cotire-gcc compatibility +set(USE_COTIRE true) +IF(CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) + IF(GCC_VERSION VERSION_LESS 4.5) + SET(USE_COTIRE false) + ENDIF() +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +# Make sure our CMake version is actually supported by cotire +IF(CMAKE_VERSION VERSION_LESS 2.8.12) + SET(USE_COTIRE false) +ENDIF() + if (USE_COTIRE) include (${DYNINST_ROOT}/cmake/cotire.cmake) endif() From dad6bb20bccc79955b8cae7c032e16c7065ffac4 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 30 Aug 2016 17:27:01 -0500 Subject: [PATCH 060/180] More cotire restrictions added. --- cmake/shared.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 01c803876b..a72b0118d6 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -105,6 +105,11 @@ IF(CMAKE_COMPILER_IS_GNUCC) ENDIF() ENDIF(CMAKE_COMPILER_IS_GNUCC) +# If we're compiling for unix, cotire only supports Intel, GCC and Clang. +IF (UNIX && NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")) + set(USE_COTIRE false) +ENDIF + # Make sure our CMake version is actually supported by cotire IF(CMAKE_VERSION VERSION_LESS 2.8.12) SET(USE_COTIRE false) From 3402dc2d9b46bfc0287e909b503fbd5e5c5906ba Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 30 Aug 2016 17:40:26 -0500 Subject: [PATCH 061/180] Testing cotire modifications --- cmake/shared.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index a72b0118d6..1dc6e56d67 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -106,9 +106,9 @@ IF(CMAKE_COMPILER_IS_GNUCC) ENDIF(CMAKE_COMPILER_IS_GNUCC) # If we're compiling for unix, cotire only supports Intel, GCC and Clang. -IF (UNIX && NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")) +IF (UNIX AND NOT (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel"))) set(USE_COTIRE false) -ENDIF +ENDIF() # Make sure our CMake version is actually supported by cotire IF(CMAKE_VERSION VERSION_LESS 2.8.12) From 5a8bf8e285a41f6dfc16e6460f777e146258f7d1 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 31 Aug 2016 10:23:55 -0700 Subject: [PATCH 062/180] space out template '>>' for pre-C++11 compatibility --- dataflowAPI/h/stackanalysis.h | 2 +- dyninstAPI/h/BPatch_object.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dataflowAPI/h/stackanalysis.h b/dataflowAPI/h/stackanalysis.h index 1604221451..94f9f52ab0 100644 --- a/dataflowAPI/h/stackanalysis.h +++ b/dataflowAPI/h/stackanalysis.h @@ -332,7 +332,7 @@ class StackAnalysis { // To avoid sucking enormous time, we keep those transfer functions around... typedef std::map > InstructionEffects; - typedef std::map> + typedef std::map > CallEffects; DATAFLOW_EXPORT StackAnalysis(); diff --git a/dyninstAPI/h/BPatch_object.h b/dyninstAPI/h/BPatch_object.h index 69c06a0e32..b60863aae5 100644 --- a/dyninstAPI/h/BPatch_object.h +++ b/dyninstAPI/h/BPatch_object.h @@ -166,7 +166,7 @@ class BPATCH_DLL_EXPORT BPatch_object { // Returns in modResults a vector of (function, instrumented) pairs where // instrumented is true if stack modifications were successfully added. void addModsAllFuncs(const std::set &mods, bool interproc, - std::vector> &modResults, + std::vector > &modResults, unsigned depthLimit = 0); BPatchSnippetHandle* insertInitCallback(BPatch_snippet& callback); From 8458404f94b16740616a915c99c87e9d2a036de1 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Thu, 1 Sep 2016 13:21:07 -0500 Subject: [PATCH 063/180] Guard StackMod implementation from non-x86 architectures. --- dyninstAPI/src/BPatch_object.C | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dyninstAPI/src/BPatch_object.C b/dyninstAPI/src/BPatch_object.C index 4dc705bb0f..ca413bc04b 100644 --- a/dyninstAPI/src/BPatch_object.C +++ b/dyninstAPI/src/BPatch_object.C @@ -31,7 +31,9 @@ #include #include +#if defined(cap_stack_mods) #include "stackanalysis.h" +#endif #include "BPatch_object.h" #include "BPatch_image.h" @@ -230,6 +232,7 @@ BPatchSnippetHandle* BPatch_object::insertFiniCallback(BPatch_snippet& callback) } +#if defined(cap_stack_mods) namespace { void getCalledFuncs(BPatch_function *func, std::set &callSet) { @@ -578,11 +581,13 @@ void addModsFuncSet(const std::set &mods, } } // namespace +#endif void BPatch_object::addModsAllFuncs(const std::set &mods, bool interproc, std::vector > &modResults, unsigned depthLimit) { +#if defined(cap_stack_mods) // Get list of functions in this object std::set allModFuncs; std::vector objModules; @@ -655,4 +660,5 @@ void BPatch_object::addModsAllFuncs(const std::set &mods, modResults.push_back(std::make_pair(func, func->addMods(mods))); } } +#endif } From abdba48fff70e88505c581398b40e7ac950836f8 Mon Sep 17 00:00:00 2001 From: Rafael Stahl Date: Tue, 6 Sep 2016 18:04:36 +0200 Subject: [PATCH 064/180] symtabAPI: dont expect a data segment in elf; eliminate dead code --- symtabAPI/src/Object-elf.C | 9 --------- 1 file changed, 9 deletions(-) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 3c4c303fde..804ee2d234 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -1538,12 +1538,6 @@ void Object::load_object(bool alloc_syms) //bpfatal( "no text segment\n"); goto cleanup; } - - if (!data_ptr_ || !data_len_) - { - //bpfatal( "no data segment\n"); - goto cleanup; - } } get_valid_memory_areas(*elfHdr); @@ -5288,9 +5282,6 @@ Dyninst::Architecture Object::getArch() default: return Dyninst::Arch_none; } - assert (0 && "default not taken!"); - return Dyninst::Arch_none; - } bool Object::getABIVersion(int &major, int &minor) const From 0bbf764670358fbae1c66345bb6b49cc9da4ef07 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 13 Sep 2016 16:05:49 -0500 Subject: [PATCH 065/180] Updated README Added a branch status block at the top. --- README | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README b/README index 35e789b980..173fa358f2 100644 --- a/README +++ b/README @@ -1,3 +1,15 @@ +BRANCH: master +STATUS: +* Known issues should have open issues associated with them. +* ARM64 support in Dataflow/ParseAPI is experimental and incomplete. +* PPC64/little endian support in read-level interfaces + (symtab, stackwalker, proccontrol) is experimental. +* PPC64/little endian support in write-level interfaces is not implemented. + +All non-API-breaking bug fixes should land here. All non-ABI-breaking +bug fixes should also land on v9.2.x. + + READ THIS FIRST: how to build DyninstAPI and its subcomponents 1) Configuration @@ -105,4 +117,4 @@ the main thread of a process * Stackwalker is fragile on Windows -* Parsing a binary with no functions (typically a single object file) will crash at CodeObject destruction time. \ No newline at end of file +* Parsing a binary with no functions (typically a single object file) will crash at CodeObject destruction time. From 4499ba0ee5d7d79bde110940b3ed16d6ecdd0cdf Mon Sep 17 00:00:00 2001 From: John Detter Date: Wed, 14 Sep 2016 12:54:07 -0500 Subject: [PATCH 066/180] Updated READMEs for Github markdown --- dataflowAPI/README.md | 3 +++ dyninstAPI/{README => README.md} | 4 ++-- parseAPI/{README => README.md} | 7 +++---- symtabAPI/README | 21 +++++---------------- 4 files changed, 13 insertions(+), 22 deletions(-) create mode 100644 dataflowAPI/README.md rename dyninstAPI/{README => README.md} (98%) rename parseAPI/{README => README.md} (96%) diff --git a/dataflowAPI/README.md b/dataflowAPI/README.md new file mode 100644 index 0000000000..efb3134662 --- /dev/null +++ b/dataflowAPI/README.md @@ -0,0 +1,3 @@ +# DataflowAPI + + diff --git a/dyninstAPI/README b/dyninstAPI/README.md similarity index 98% rename from dyninstAPI/README rename to dyninstAPI/README.md index c320a48aab..459e3fc197 100644 --- a/dyninstAPI/README +++ b/dyninstAPI/README.md @@ -1,3 +1,4 @@ +# DyninstAPI This is the version 9.1 release of the Dyninst API. Currently, the API library is available for the POWER/Linux, x86/Linux, x86_64/Linux, and @@ -12,8 +13,7 @@ that test the API functions. These programs are useful as examples of how to use the API. See the README file in that directory for how to run or rebuild them. -Setting up the environment --------------------------- +## Setting up the environment DYNINSTAPI_RT_LIB should be set to the full pathname of the file libdyninstAPI_RT.so (on Windows, libdyninstAPI_RT.dll). diff --git a/parseAPI/README b/parseAPI/README.md similarity index 96% rename from parseAPI/README rename to parseAPI/README.md index 978bb6f877..cd31eb0162 100644 --- a/parseAPI/README +++ b/parseAPI/README.md @@ -1,3 +1,4 @@ +# ParseAPI This is release 9.1 of the ParseAPI. Currently, this library is available for the x86[_64]/Linux, x86/Windows, and @@ -10,8 +11,7 @@ Documentation for the API can be found at as well as in the doc/ subdirectory. -Prerequisites --------------------------- +## Prerequisites The ParseAPI is a component of the Dyninst system, and depends on two other components: the SymtabAPI binary format library and the InstructionAPI @@ -23,8 +23,7 @@ The SymtabAPI has further dependencies depending on the platform, including libelf and libdwarf. See the SymtabAPI documentation for details. -Compiling the library --------------------------- +## Compiling the library See the top-level INSTALL file for build information. diff --git a/symtabAPI/README b/symtabAPI/README index 102291496b..54754edcbb 100644 --- a/symtabAPI/README +++ b/symtabAPI/README @@ -1,16 +1,6 @@ - *** Symtab 9.1 Release Notes *** +# SymtabAPI -This is the version 9.1 release of the SymtabAPI. Currently, the API -library is available for ELF platforms (Linux, BlueGene), and PE -platforms (Windows). - -Documentation for the Symtab API can be found at: - - http://www.dyninst.org/ - - -Prerequisites -------------- +## Prerequisites On Linux, Symtab requires some libraries that are not installed by default in most distributions. The first is libelf, which is included with most @@ -19,13 +9,12 @@ The second is libdwarf. You can get the latest source code distribution of libdwarf from http://sourceforge.net/projects/libdwarf/. RPM files for libdwarf are also available from various sites. -Building the SymtabAPI from source ------------------------------------- +## Building the SymtabAPI from source See the top-level INSTALL file for how to build. -Changes since 9.0 ------------------ +### Changes since 9.0 + - Speed and space optimizations - Fixes for bugs reading line information - Fixes for bugs reading exception information From 16ccee18b807800bbb08638607d6302df831eb76 Mon Sep 17 00:00:00 2001 From: Sunny Shah Date: Wed, 14 Sep 2016 12:54:12 -0500 Subject: [PATCH 067/180] When determining the ROSE register category for ARM registers, comparisions of the MachRegisters with 'baseID' should only use the MachRegister's lowermost 16 bits. --- common/src/dyn_regs.C | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/dyn_regs.C b/common/src/dyn_regs.C index 3a8ca0bea3..dee9b39559 100644 --- a/common/src/dyn_regs.C +++ b/common/src/dyn_regs.C @@ -813,7 +813,7 @@ void MachRegister::getROSERegister(int &c, int &n, int &p) switch(category) { case aarch64::GPR: { c = armv8_regclass_gpr; - if(baseID == aarch64::zr || baseID == aarch64::wzr) + if(baseID == (aarch64::zr & 0xFF) || baseID == (aarch64::wzr & 0xFF)) n = armv8_gpr_zr; else { int regnum = baseID - aarch64::x0; @@ -823,12 +823,12 @@ void MachRegister::getROSERegister(int &c, int &n, int &p) break; case aarch64::SPR: { n = 0; - if(baseID == aarch64::pstate) { + if(baseID == (aarch64::pstate & 0xFF)) { c = armv8_regclass_pstate; p = armv8_pstatefield_nzcv; - } else if(baseID == aarch64::pc) { + } else if(baseID == (aarch64::pc & 0xFF)) { c = armv8_regclass_pc; - } else if(baseID == aarch64::sp || baseID == aarch64::wsp) { + } else if(baseID == (aarch64::sp & 0xFF) || baseID == (aarch64::wsp & 0xFF)) { c = armv8_regclass_sp; } } From 3bd0376e70a01569beaafd95310ee2f1b518ceb7 Mon Sep 17 00:00:00 2001 From: John Detter Date: Wed, 14 Sep 2016 14:01:22 -0500 Subject: [PATCH 068/180] More Github formatting --- dyninstAPI/README.md | 6 +++--- symtabAPI/{README => README.md} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename symtabAPI/{README => README.md} (100%) diff --git a/dyninstAPI/README.md b/dyninstAPI/README.md index 459e3fc197..ccdb47fdf5 100644 --- a/dyninstAPI/README.md +++ b/dyninstAPI/README.md @@ -45,10 +45,11 @@ This software is derived from the Paradyn system and therefore subject to the same copyright. A copy of the Paradyn copyright appears at the end of this file. - The Dyninst API Team - 12/9/2015 +The Dyninst API Team +12/9/2015 ----------------------- Start of Paradyn Copyright -------------------------- + See the dyninst/COPYRIGHT file for copyright information. We provide the Paradyn Tools (below described as "Paradyn") @@ -76,4 +77,3 @@ 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 - diff --git a/symtabAPI/README b/symtabAPI/README.md similarity index 100% rename from symtabAPI/README rename to symtabAPI/README.md From 82a57100bb9adcc2f633f008dd94cb5fb94d8901 Mon Sep 17 00:00:00 2001 From: Sunny Shah Date: Sun, 18 Sep 2016 18:39:47 -0500 Subject: [PATCH 069/180] The argument to SymEvalSemantics::addWithCarries for unsign-extending the second addend should be the second operand from the instruction AST. The bug here was that the first operand from the AST was being passed for the unsign-extend operation. This caused the semantic expression and hence the resulting assignment expansion for the instructions calling this function to be incorrect. --- dataflowAPI/rose/semantics/SymEvalSemantics.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataflowAPI/rose/semantics/SymEvalSemantics.C b/dataflowAPI/rose/semantics/SymEvalSemantics.C index 043c64895c..0849033654 100644 --- a/dataflowAPI/rose/semantics/SymEvalSemantics.C +++ b/dataflowAPI/rose/semantics/SymEvalSemantics.C @@ -228,7 +228,7 @@ BaseSemantics::SValuePtr SymEvalSemantics::RiscOperatorsARM64::addWithCarries(co const BaseSemantics::SValuePtr &c_, BaseSemantics::SValuePtr &carry_out) { BaseSemantics::SValuePtr aa_ = unsignedExtend(a_, a_->get_width() + 1); - BaseSemantics::SValuePtr bb_ = unsignedExtend(a_, b_->get_width() + 1); + BaseSemantics::SValuePtr bb_ = unsignedExtend(b_, b_->get_width() + 1); BaseSemantics::SValuePtr sum_ = createBinaryAST(Dyninst::DataflowAPI::ROSEOperation::addOp, aa_, createBinaryAST(Dyninst::DataflowAPI::ROSEOperation::addOp, bb_, c_)); From 99b0c68251159005b4034cc5ae18361fadff0064 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 01:58:57 -0500 Subject: [PATCH 070/180] Markdown updates --- symtabAPI/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/symtabAPI/README.md b/symtabAPI/README.md index 54754edcbb..dd47250c93 100644 --- a/symtabAPI/README.md +++ b/symtabAPI/README.md @@ -20,6 +20,7 @@ See the top-level INSTALL file for how to build. - Fixes for bugs reading exception information ----------------------------------------------------------------------------- + This software is derived from the Paradyn system and therefore subject to the same copyright. A copy of the Paradyn copyright appears at the end of this file. @@ -28,6 +29,7 @@ this file. 12/9/2015 ----------------------- Start of Paradyn Copyright -------------------------- + See the dyninst/COPYRIGHT file for copyright information. We provide the Paradyn Tools (below described as "Paradyn") From 59b4ff24ed68db47144d8819b2286394e221dc7a Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 01:54:57 -0500 Subject: [PATCH 071/180] Update README.md --- dataflowAPI/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dataflowAPI/README.md b/dataflowAPI/README.md index efb3134662..7f79970f17 100644 --- a/dataflowAPI/README.md +++ b/dataflowAPI/README.md @@ -1,3 +1,7 @@ # DataflowAPI +## Branch states +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | No open issues | From 60407c04647e6558fb7f960a602cf1e4768d34f5 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:14:28 -0500 Subject: [PATCH 072/180] Renamed and updated README for parseThat --- parseThat/{README => README.md} | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) rename parseThat/{README => README.md} (96%) diff --git a/parseThat/README b/parseThat/README.md similarity index 96% rename from parseThat/README rename to parseThat/README.md index 0de0d66a1d..08662a98f8 100644 --- a/parseThat/README +++ b/parseThat/README.md @@ -1,4 +1,6 @@ -INTRODUCTION +# parseThat + +## Introduction parseThat is an application that provides a rigorous and robust test of DyninstAPI on arbitrary binaries. Geared mainly for debugging purposes, @@ -7,7 +9,7 @@ parseThat generates copious output for each dyninstAPI feature it uses. These output logs can be used to quickly locate the source of parsing or instrumentation bugs, in the rare instance when they occur. -CONFIGURATION +## Configuration Autoconf scripts are used to gather information about the target platform before building. The top level Makefile, however, will issue configure commands. @@ -37,7 +39,7 @@ built. variable to manually specify where you placed a source or binary distribution of DyninstAPI. -BUILDING & INSTALLING +## Building and Installing To build parseThat from scratch, issue the make command. This will create a platform-specific build directory, configure the Makefile, and build @@ -47,7 +49,7 @@ commands to the platform specific Makefile in the $PLATFORM directory. Once successfully built, invoking GNU make with the "install" target will copy the binary to its final destination. -RUNNING +## RUNNING Documentation on running parseThat is encoded within the binary itself. It can be viewed by simply running parseThat with the --help flag. From 10fda35aace16cf959152cdec217c4ff7dc0f733 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:01:50 -0500 Subject: [PATCH 073/180] Update README.md --- dyninstAPI/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dyninstAPI/README.md b/dyninstAPI/README.md index ccdb47fdf5..f5d512eee9 100644 --- a/dyninstAPI/README.md +++ b/dyninstAPI/README.md @@ -1,5 +1,11 @@ # DyninstAPI +## Branch states + +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | No open issues | + This is the version 9.1 release of the Dyninst API. Currently, the API library is available for the POWER/Linux, x86/Linux, x86_64/Linux, and x86/Windows XP/2000/2003/Windows 7 platforms. From fd50a28a93f1a83247f0b4b0631a2aea625fabad Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:02:39 -0500 Subject: [PATCH 074/180] Update README.md --- parseAPI/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parseAPI/README.md b/parseAPI/README.md index cd31eb0162..fb24c7e5fb 100644 --- a/parseAPI/README.md +++ b/parseAPI/README.md @@ -1,5 +1,11 @@ # ParseAPI +## Branch states + +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | No open issues | + This is release 9.1 of the ParseAPI. Currently, this library is available for the x86[_64]/Linux, x86/Windows, and POWER/Linux platforms. From 76071a8dad1cdf1ab0a80214a707e551b4fecbc6 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:15:53 -0500 Subject: [PATCH 075/180] Update README.md --- parseThat/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parseThat/README.md b/parseThat/README.md index 08662a98f8..6cfe5671ce 100644 --- a/parseThat/README.md +++ b/parseThat/README.md @@ -49,7 +49,7 @@ commands to the platform specific Makefile in the $PLATFORM directory. Once successfully built, invoking GNU make with the "install" target will copy the binary to its final destination. -## RUNNING +## Running Documentation on running parseThat is encoded within the binary itself. It can be viewed by simply running parseThat with the --help flag. From a7a311c1fdf5229a77e7e920648c7d28abea9414 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:16:40 -0500 Subject: [PATCH 076/180] Create README.md --- proccontrol/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 proccontrol/README.md diff --git a/proccontrol/README.md b/proccontrol/README.md new file mode 100644 index 0000000000..e8cdb24f71 --- /dev/null +++ b/proccontrol/README.md @@ -0,0 +1,7 @@ +# Proccontrol + +## Branch states + +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | No open issues | From 3940000f073c6ec3ee483084168cd0fbe4a8456a Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:17:23 -0500 Subject: [PATCH 077/180] Create README.md --- stackwalk/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 stackwalk/README.md diff --git a/stackwalk/README.md b/stackwalk/README.md new file mode 100644 index 0000000000..247f114816 --- /dev/null +++ b/stackwalk/README.md @@ -0,0 +1,7 @@ +# Stackwalk + +## Branch states + +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | No open issues | From 1485068c0d2fd6c8cde0eb22bd92a0cddadcac6f Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:17:43 -0500 Subject: [PATCH 078/180] Update README.md --- symtabAPI/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/symtabAPI/README.md b/symtabAPI/README.md index dd47250c93..58c9f81ab8 100644 --- a/symtabAPI/README.md +++ b/symtabAPI/README.md @@ -1,5 +1,11 @@ # SymtabAPI +## Branch states + +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | No open issues | + ## Prerequisites On Linux, Symtab requires some libraries that are not installed by default From a005c8dab2a825cf8609f59c680592d1959d3373 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:18:08 -0500 Subject: [PATCH 079/180] Create README.md --- symlite/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 symlite/README.md diff --git a/symlite/README.md b/symlite/README.md new file mode 100644 index 0000000000..4cbacef6e1 --- /dev/null +++ b/symlite/README.md @@ -0,0 +1,7 @@ +# Symlite + +## Branch states + +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | No open issues | From 206fe6a487bf1727a19d3729f1fbc95f9ef8f307 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:21:55 -0500 Subject: [PATCH 080/180] Update and rename README to README.md --- README => README.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) rename README => README.md (92%) diff --git a/README b/README.md similarity index 92% rename from README rename to README.md index 173fa358f2..6d1f53e3e7 100644 --- a/README +++ b/README.md @@ -1,5 +1,13 @@ -BRANCH: master -STATUS: +# Dyninst + +## Branch states + +| Branch | Status | +| --------------------------------------- |:-------------:| +| master | stable | + +## Notes + * Known issues should have open issues associated with them. * ARM64 support in Dataflow/ParseAPI is experimental and incomplete. * PPC64/little endian support in read-level interfaces @@ -9,10 +17,9 @@ STATUS: All non-API-breaking bug fixes should land here. All non-ABI-breaking bug fixes should also land on v9.2.x. +## Build DyninstAPI and its subcomponents -READ THIS FIRST: how to build DyninstAPI and its subcomponents - -1) Configuration +### Configuration Dyninst is now built via CMake. We recommend performing an interactive configuration with "ccmake ." first, in order to see which options are @@ -46,7 +53,7 @@ manually define the appropriate compiler, library locations, include locations, and the CROSS_COMPILING flag so that the build system will properly evaluate what can be built and linked in your environment. -2) Building and installation +### Building and installing To build Dyninst and all its components, "make && make install" from the top-level directory of the source tree. To build and install a @@ -62,7 +69,7 @@ them. Components may be built and installed individually: "make $COMPONENT" and "make $COMPONENT-install" respectively; this will appropriately respect inter-component dependencies. -3) What's new +## What's new NEW FEATURES: @@ -75,7 +82,7 @@ NEW FEATURES: * Initial ppc64/little endian support in Symtab, InstructionAPI, ProcControl, and Stackwalker. Add -Darch_ppc64_little_endian to your CMake command line when building on little-endian ppc64 systems. -BUG FIXES +## Bug fixes * PIE binaries should now be rewritten correctly, even if they have a zero base address @@ -96,7 +103,7 @@ BUG FIXES * ppc64 bit rot for create/attach modes is fixed -KNOWN ISSUES +## Known Issues * ppc64 rewriter mode does not handle any code that does not conform to the "caller sets up TOC" model for intermodule calls From d0a7e8d0c24269a8dc3ef2047f99a877fe7b4032 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 20 Sep 2016 02:25:56 -0500 Subject: [PATCH 081/180] Update README.md --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6d1f53e3e7..a9d3be27ff 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ ## Branch states -| Branch | Status | -| --------------------------------------- |:-------------:| -| master | stable | +| Branch | Status | Notes | +| --------------------------------------- |:-------------:|:--------------------------------------------------:| +| master | stable | See below | +| arm64 | experimental | | ## Notes @@ -27,6 +28,7 @@ relevant for your system. You may also perform a batch configuration with "cmake .". Options are passed to CMake with -DVAR=VALUE. Common options include: +``` Boost_INCLUDE_DIR CMAKE_BUILD_TYPE CMAKE_INSTALL_PREFIX @@ -35,6 +37,7 @@ LIBDWARF_LIBRARIES LIBELF_INCLUDE_DIR LIBELF_LIBRARIES IBERTY_LIBRARIES +``` CMake's default generator on Linux is normally "Unix Makefiles", and on Windows, it will normally produce project files for the most recent @@ -59,11 +62,11 @@ To build Dyninst and all its components, "make && make install" from the top-level directory of the source tree. To build and install a single component and its dependencies, do the same thing from that component's subdirectory. Libraries will be installed into -CMAKE_INSTALL_PREFIX/INSTALL_LIB_DIR, and headers will be installed -into CMAKE_INSTALL_PREFIX/INSTALL_INCLUDE_DIR. If you wish to import +`CMAKE_INSTALL_PREFIX/INSTALL_LIB_DIR`, and headers will be installed +into `CMAKE_INSTALL_PREFIX/INSTALL_INCLUDE_DIR`. If you wish to import Dyninst into your own CMake projects, the export information is in -CMAKE_INSTALL_PREFIX/INSTALL_CMAKE_DIR. PDF documentation is included -and installed to CMAKE_INSTALL_PREFIX/INSTALL_DOC_DIR. If you update +`CMAKE_INSTALL_PREFIX/INSTALL_CMAKE_DIR`. PDF documentation is included +and installed to `CMAKE_INSTALL_PREFIX/INSTALL_DOC_DIR`. If you update the LaTeX source documents for any manuals, "make doc" will rebuild them. Components may be built and installed individually: "make $COMPONENT" and "make $COMPONENT-install" respectively; this will @@ -96,7 +99,7 @@ NEW FEATURES: * Various proccontrol bug fixes -* RTlib's DYNINSTos_malloc and DYNINSTos_free should now be signal-safe +* RTlib's `DYNINSTos_malloc` and `DYNINSTos_free` should now be signal-safe * RTlib's tramp guard lock/unlock functions should now avoid making implicit function calls (which are unsafe from tramp guard code) From f42fb50ecaa87c307b03fd7a3c5b3368a38cb400 Mon Sep 17 00:00:00 2001 From: Rafael Stahl Date: Tue, 6 Sep 2016 17:30:12 +0200 Subject: [PATCH 082/180] elf: fix uninitialized isBigEndian for archives; duplicate code removal --- elf/src/Elf_X.C | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index 23c4befc3b..84609a2005 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -135,16 +135,10 @@ Elf_X::Elf_X(int input, Elf_Cmd cmd, Elf_X *ref) elf = elf_begin(input, cmd, NULL); } if (elf) { - if (elf_kind(elf) == ELF_K_ELF) { - char *identp = elf_getident(elf, NULL); - is64 = (identp && identp[EI_CLASS] == ELFCLASS64); - isBigEndian = (identp && identp[EI_DATA] == ELFDATA2MSB); - } - else if(elf_kind(elf) == ELF_K_AR) { - char *identp = elf_getident(elf, NULL); - is64 = (identp && identp[EI_CLASS] == ELFCLASS64); - isArchive = true; - } + char *identp = elf_getident(elf, NULL); + is64 = (identp && identp[EI_CLASS] == ELFCLASS64); + isBigEndian = (identp && identp[EI_DATA] == ELFDATA2MSB); + isArchive = (elf_kind(elf) == ELF_K_AR); if (!is64) ehdr32 = elf32_getehdr(elf); else ehdr64 = elf64_getehdr(elf); From 86368f17af0c516ba439ca44a3ef770c6d3d2ae3 Mon Sep 17 00:00:00 2001 From: Rafael Stahl Date: Sun, 25 Sep 2016 21:15:54 +0200 Subject: [PATCH 083/180] cmake: Fix not building when libiberty is automatically installed --- cmake/packages.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index 0249f5ba8a..4f9160a703 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -69,6 +69,7 @@ if (UNIX) INSTALL_COMMAND install /libiberty.a ) set(IBERTY_LIBRARIES ${CMAKE_BINARY_DIR}/libiberty/libiberty.a) + set(IBERTY_FOUND TRUE) endif() message(STATUS "Using libiberty ${IBERTY_LIBRARIES}") From d389b2f16af8c0a7646c4f8549756a1e765ccf6c Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 1 Jul 2016 14:35:16 -0400 Subject: [PATCH 084/180] cmake cleanup --- CMakeLists.txt | 26 ++++---------------------- dynutil/CMakeLists.txt | 3 --- 2 files changed, 4 insertions(+), 25 deletions(-) delete mode 100644 dynutil/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e720a4d97b..b3e02847d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,11 +19,9 @@ include (${DYNINST_ROOT}/cmake/shared.cmake) configure_file(cmake/version.h.in common/h/version.h) include_directories(${PROJECT_BINARY_DIR}) include_directories(${PROJECT_BINARY_DIR}/common/h) -if(${PLATFORM} MATCHES nt) - set (HEADER_DIRS common +set (HEADER_DIRS common dataflowAPI dyninstAPI - dynutil instructionAPI parseAPI patchAPI @@ -31,20 +29,11 @@ if(${PLATFORM} MATCHES nt) stackwalk symtabAPI ) -else() - set (HEADER_DIRS common - dataflowAPI +if(NOT ${PLATFORM} MATCHES nt) + set (HEADER_DIRS ${HEADER_DIRS} dwarf - dyninstAPI - dynutil elf - instructionAPI - parseAPI - patchAPI - proccontrol - stackwalk symlite - symtabAPI ) endif() @@ -163,7 +152,6 @@ if(BUILD_DOCS) ) endforeach() - #set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE) find_package(LATEX) if(PDFLATEX_COMPILER) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/common/doc @@ -173,11 +161,9 @@ if(BUILD_DOCS) DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}) set (DEPS "") file(GLOB_RECURSE DEPS ${CMAKE_CURRENT_SOURCE_DIR}/${COMPONENT}/doc/*.tex ${CMAKE_CURRENT_SOURCE_DIR}/common/doc/*.tex) - #message(STATUS "Found dependencies for ${COMPONENT} manual: ${DEPS}") add_custom_command( - # OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${COMPONENT}/doc/${COMPONENT}.aux OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}/doc/${COMPONENT}.aux - DEPENDS ${DEPS} #${CMAKE_CURRENT_SOURCE_DIR}/${COMPONENT}/doc/${COMPONENT}.tex + DEPENDS ${DEPS} COMMAND ${PDFLATEX_COMPILER} ARGS -interaction=batchmode ${COMPONENT}.tex WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}/doc @@ -186,20 +172,16 @@ if(BUILD_DOCS) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}/doc/${COMPONENT}.log DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}/doc/${COMPONENT}.aux - # OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${COMPONENT}/doc/${COMPONENT}.log - # DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${COMPONENT}/doc/${COMPONENT}.aux COMMAND ${PDFLATEX_COMPILER} ARGS -interaction=batchmode ${COMPONENT}.tex WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}/doc COMMENT "Latex (second pass)" ) add_custom_target(${COMPONENT}-doc echo - # DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${COMPONENT}/doc/${COMPONENT}.log DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}/doc/${COMPONENT}.log ) add_dependencies(doc ${COMPONENT}-doc) set_target_properties(${COMPONENT}-doc PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1) - #add_dependencies(${COMPONENT} ${COMPONENT}-doc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${COMPONENT}/doc/${COMPONENT}.pdf DESTINATION ${INSTALL_DOC_DIR} RENAME ${COMPONENT}-${VERSION_STRING}.pdf diff --git a/dynutil/CMakeLists.txt b/dynutil/CMakeLists.txt deleted file mode 100644 index 3649b7afdc..0000000000 --- a/dynutil/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# CMake configuration for dynutil directory - -INSTALL (DIRECTORY h/ DESTINATION include FILES_MATCHING PATTERN "*.h") From fed8d78cf99b444a06ba108b97609541e61dc2bf Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 1 Jul 2016 16:05:16 -0400 Subject: [PATCH 085/180] fix dyninstAPI warnings --- dyninstAPI_RT/src/RTheap-win.c | 3 ++- dyninstAPI_RT/src/RTwinnt.c | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/dyninstAPI_RT/src/RTheap-win.c b/dyninstAPI_RT/src/RTheap-win.c index e0c33701a7..13c2dbf5f1 100644 --- a/dyninstAPI_RT/src/RTheap-win.c +++ b/dyninstAPI_RT/src/RTheap-win.c @@ -29,6 +29,7 @@ */ #include +#include #include "dyninstAPI_RT/src/RTheap.h" #include "dyninstAPI_RT/src/RTcommon.h" @@ -51,7 +52,7 @@ int getpagesize() { void *map_region(void *addr, int len, int fd) { void *result; DWORD lastError; - char* lpMessage; + char* lpMessage = NULL; result = VirtualAlloc(addr, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(!result) { lastError = GetLastError(); diff --git a/dyninstAPI_RT/src/RTwinnt.c b/dyninstAPI_RT/src/RTwinnt.c index 39b14695df..b1c55a5735 100644 --- a/dyninstAPI_RT/src/RTwinnt.c +++ b/dyninstAPI_RT/src/RTwinnt.c @@ -36,6 +36,7 @@ #include "RTcommon.h" #include #include +#include #include #include #include @@ -142,7 +143,7 @@ int DYNINSTasyncConnect(int mutatorpid) int sock_fd; struct sockaddr_in sadr; struct in_addr *inadr; - struct hostent *hostptr; + struct addrinfo *result = NULL; WORD wsversion = MAKEWORD(2,0); WSADATA wsadata; @@ -166,8 +167,8 @@ int DYNINSTasyncConnect(int mutatorpid) RTprintf("%s[%d]: DYNINSTasyncConnect before gethostbyname\n", __FILE__, __LINE__); - hostptr = gethostbyname("localhost"); - inadr = (struct in_addr *) ((void*) hostptr->h_addr_list[0]); + getaddrinfo("localhost", NULL, NULL, &result); + inadr = (struct in_addr *) result->ai_addr; RTprintf("%s[%d]: inside DYNINSTasyncConnect before memset\n", __FILE__, __LINE__); @@ -214,6 +215,8 @@ int DYNINSTasyncConnect(int mutatorpid) RTprintf("%s[%d]: leaving DYNINSTasyncConnect\n", __FILE__, __LINE__); + freeaddrinfo(result); + return 1; /*true*/ } @@ -361,7 +364,7 @@ static struct trap_mapping_header *getStaticTrapMap(unsigned long addr, unsigned + curSecn.SizeOfRawData - 16); if (0 != strncmp("DYNINST_REWRITE", str, 15)) { - fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap found bad string [%s] at %lx %s[%d]\n", + fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap found bad string [%s] at %p (%s[%d])\n", str, str, __FILE__,__LINE__); goto done; // doesn't have DYNINST_REWRITE label } @@ -397,7 +400,7 @@ LONG dyn_trapHandler(PEXCEPTION_POINTERS e) if (EXCEPTION_BREAKPOINT != e->ExceptionRecord->ExceptionCode) { fprintf(stderr,"RTLIB: dyn_trapHandler exiting early, exception " - "type = 0x%lx triggered at 0x%lx is not breakpoint %s[%d]\n", + "type = 0x%lx triggered at %p is not breakpoint %s[%d]\n", e->ExceptionRecord->ExceptionCode, trap_addr, __FILE__,__LINE__); return EXCEPTION_CONTINUE_SEARCH; } @@ -475,14 +478,14 @@ BOOL __stdcall DYNINST_FakeBlockInput(BOOL blockit) DWORD __stdcall DYNINST_FakeSuspendThread(HANDLE hThread) { DWORD suspendCnt = 0; - fprintf(stOut,"%d = DYNINST_FakeSuspendThread(%d)\n",suspendCnt,hThread); + fprintf(stOut,"%d = DYNINST_FakeSuspendThread(%p)\n",suspendCnt,hThread); return suspendCnt; } BOOL __stdcall DYNINST_FakeCheckRemoteDebuggerPresent(HANDLE hProcess, PBOOL bpDebuggerPresent) { BOOL ret = RT_FALSE; - fprintf(stOut,"%d = DYNINST_FakeCheckRemoteDebuggerPresent(%d,0x%lx)\n", + fprintf(stOut,"%d = DYNINST_FakeCheckRemoteDebuggerPresent(%p,%p)\n", ret, hProcess, bpDebuggerPresent); (*bpDebuggerPresent) = ret; return ret; From db925d4096b4984bf01433a661e6b90296e29aa2 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 1 Jul 2016 16:16:07 -0400 Subject: [PATCH 086/180] fix instructionAPI warning --- instructionAPI/src/InstructionDecoder-aarch64.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instructionAPI/src/InstructionDecoder-aarch64.C b/instructionAPI/src/InstructionDecoder-aarch64.C index c8af4ddd8f..2e01366c72 100644 --- a/instructionAPI/src/InstructionDecoder-aarch64.C +++ b/instructionAPI/src/InstructionDecoder-aarch64.C @@ -2289,7 +2289,7 @@ Expression::Ptr InstructionDecoder_aarch64::makeMemRefExPair2(){ int immLen) { Expression::Ptr lhs = makePCExpr(); - int offset = sign_extend64(immLen + 2, immVal * 4); + int64_t offset = sign_extend64(immLen + 2, immVal * 4); Expression::Ptr rhs = Immediate::makeImmediate(Result(s64, offset)); insn_in_progress->addSuccessor(makeAddExpression(lhs, rhs, s64), branchIsCall, false, bIsConditional, From 3908f8486c7ce273755e47a6d7cf0f9aa6845137 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 1 Jul 2016 16:21:25 -0400 Subject: [PATCH 087/180] fix symtabAPI warnings --- symtabAPI/src/Object-nt.C | 12 ++++++------ symtabAPI/src/emitWin.C | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index c0d6b9cf19..e301d0eb0f 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -817,7 +817,7 @@ void Object::FindInterestingSections(bool alloc_syms, bool defensive) code_len_ = mf->size(); is_aout_ = false; fprintf(stderr,"Adding Symtab object with no program header, will " - "designate it as code, code_ptr_=%lx code_len_=%lx\n", + "designate it as code, code_ptr_=%s code_len_=%lx\n", code_ptr_,code_len_); if (alloc_syms) { Region *bufReg = new Region @@ -1698,7 +1698,7 @@ static Type *getUDTType(HANDLE p, Offset base, int typeIndex, Module *mod) { std::string tName = convertCharToString(name); result = SymGetTypeInfo(p, base, typeIndex, TI_GET_LENGTH, &size64); if (!result) { - fprintf(stderr, "[%s:%u] - TI_GET_LENGTH return error\n"); + fprintf(stderr, "%s - TI_GET_LENGTH return error\n", name); return NULL; } size = (unsigned) size64; @@ -1709,7 +1709,7 @@ static Type *getUDTType(HANDLE p, Offset base, int typeIndex, Module *mod) { // result = SymGetTypeInfo(p, base, typeIndex, TI_GET_UDTKIND, &udtType); if (!result) { - fprintf(stderr, "[%s:%u] - TI_GET_UDTKIND returned error\n"); + fprintf(stderr, "%s - TI_GET_UDTKIND returned error\n", name); return NULL; } switch (udtType) { @@ -1889,13 +1889,13 @@ static Type *getBaseType(HANDLE p, Offset base, int typeIndex, Module *mod) { result = SymGetTypeInfo(p, base, typeIndex, TI_GET_BASETYPE, &baseType); if (!result) { - fprintf(stderr, "[%s:%u] - TI_GET_BASETYPE return error\n"); + fprintf(stderr, "TI_GET_BASETYPE return error\n"); return NULL; } result = SymGetTypeInfo(p, base, typeIndex, TI_GET_LENGTH, &size64); if (!result) { - fprintf(stderr, "[%s:%u] - TI_GET_LENGTH return error\n"); + fprintf(stderr, "TI_GET_LENGTH return error\n"); return NULL; } size = (unsigned) size64; @@ -2446,7 +2446,7 @@ void Object::applyRelocs(Region* relocs, Offset delta) } break; default: - fprintf(stderr, "Unknown relocation type 0x%x for addr %p\n", type, addr); + fprintf(stderr, "Unknown relocation type 0x%x for addr %lx\n", type, addr); break; } } diff --git a/symtabAPI/src/emitWin.C b/symtabAPI/src/emitWin.C index a25926fe75..49c6cd8d4b 100644 --- a/symtabAPI/src/emitWin.C +++ b/symtabAPI/src/emitWin.C @@ -468,7 +468,7 @@ bool emitWin::driver(Symtab *obj, std::string fName){ //write the PE file header //write NT header - NTHeader->FileHeader.NumberOfSections = regs.size(); + NTHeader->FileHeader.NumberOfSections = (WORD)regs.size(); //update SizeOfImage NTHeader->OptionalHeader.SizeOfImage = secHdrs[secHdrs.size()-1]->VirtualAddress + secHdrs[secHdrs.size()-1]->Misc.VirtualSize; From 006dd7130c1be4627e8e8355e081d91122a935ba Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 1 Jul 2016 16:59:00 -0400 Subject: [PATCH 088/180] fix parseAPI/dataflowAPI warnings --- dataflowAPI/rose/SgAsmPowerpcInstruction.h | 2 +- dataflowAPI/src/SymEvalPolicy.C | 1 + dataflowAPI/src/Visitors.C | 4 ++-- external/stdint-win.h | 2 +- parseAPI/src/BoundFactData.C | 16 ++++++++-------- parseAPI/src/BoundFactData.h | 2 +- parseAPI/src/IndirectASTVisitor.C | 10 +++++----- parseAPI/src/JumpTablePred.C | 6 +++--- parseAPI/src/ProbabilisticParser.C | 2 +- 9 files changed, 23 insertions(+), 22 deletions(-) diff --git a/dataflowAPI/rose/SgAsmPowerpcInstruction.h b/dataflowAPI/rose/SgAsmPowerpcInstruction.h index cbdf3f0490..1c63024503 100644 --- a/dataflowAPI/rose/SgAsmPowerpcInstruction.h +++ b/dataflowAPI/rose/SgAsmPowerpcInstruction.h @@ -52,7 +52,7 @@ class SgAsmPowerpcInstruction : public SgAsmInstruction powerpc_unknown_instruction); protected: - unsigned int p_address; + rose_addr_t p_address; PowerpcInstructionKind p_kind; SgAsmOperandList* p_operandList; std::string p_mnemonic; diff --git a/dataflowAPI/src/SymEvalPolicy.C b/dataflowAPI/src/SymEvalPolicy.C index 9eea90b2aa..c18cc9f378 100644 --- a/dataflowAPI/src/SymEvalPolicy.C +++ b/dataflowAPI/src/SymEvalPolicy.C @@ -351,6 +351,7 @@ Absloc SymEvalPolicy_64::convert(PowerpcRegisterClass regtype, int regNum) case powerpc_last_register_class:break; } assert(0); + return Absloc(); } Absloc SymEvalPolicy_64::convert(X86GeneralPurposeRegister r) diff --git a/dataflowAPI/src/Visitors.C b/dataflowAPI/src/Visitors.C index 6384241e0d..6731d44c54 100644 --- a/dataflowAPI/src/Visitors.C +++ b/dataflowAPI/src/Visitors.C @@ -107,8 +107,8 @@ AST::Ptr StackVisitor::visit(RoseAST *r) { ConstantAST::Ptr val = ConstantAST::convert(newKids[0]); unsigned long mask = 0; - for (unsigned i = from->val().val; i <= to->val().val; ++i) { - mask |= 1 << i; + for (uint64_t i = from->val().val; i <= to->val().val; ++i) { + mask |= 1 << i; } return ConstantAST::create(Constant(val->val().val & mask, to->val().val - from->val().val)); diff --git a/external/stdint-win.h b/external/stdint-win.h index 33dfd0691b..9d0d6f9eb1 100644 --- a/external/stdint-win.h +++ b/external/stdint-win.h @@ -221,7 +221,7 @@ typedef uint64_t uintmax_t; // 7.18.4 Limits of other integer types -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) && (_MSC_VER < 1600) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants diff --git a/parseAPI/src/BoundFactData.C b/parseAPI/src/BoundFactData.C index 16de220cbb..dadf7a29a0 100644 --- a/parseAPI/src/BoundFactData.C +++ b/parseAPI/src/BoundFactData.C @@ -87,7 +87,7 @@ void StridedInterval::Join(const StridedInterval &rhs) { // same constants. Nothing needs to be done if (values.size() != 1) { // Otherwise, new stride is GCD(stride, rhs.stride, |low - rhs.low|) - int newStride = GCD(stride, rhs.stride); + int64_t newStride = GCD(stride, rhs.stride); set::iterator cur, next; for (cur = values.begin(), next = values.begin(), ++next; next != values.end(); ++cur, ++next) newStride = GCD(newStride, *next - *cur); @@ -310,7 +310,7 @@ void StridedInterval::Intersect(StridedInterval &rhs) { k1 *= x; k2 *= -x; - int newStride = stride * rhs.stride / GCD(stride, rhs.stride); + int64_t newStride = stride * rhs.stride / GCD(stride, rhs.stride); int64_t newLow = low + k1 * stride, newHigh = high; if (newLow < low) newLow += ((low - newLow - 1) / newStride + 1) * newStride; if (newLow < rhs.low) newLow += ((rhs.low - newLow - 1) / newStride + 1) * newStride; @@ -510,11 +510,11 @@ void BoundValue::Add(const BoundValue &rhs) { } // Then check if we find the target base else if (tableReadSize && !isInverted && rhs.interval.IsConst() && !rhs.tableReadSize) { - targetBase = rhs.interval.low; + targetBase = (Address)rhs.interval.low; } else if (rhs.tableReadSize && !rhs.isInverted && interval.IsConst() && !tableReadSize) { int64_t val = interval.low; *this = rhs; - targetBase = val; + targetBase = (Address)val; } // In other case, we only track the values else { @@ -627,8 +627,8 @@ static bool IsTableIndex(set &values) { void BoundValue::MemoryRead(Block* b, int readSize) { if (interval != StridedInterval::top) { - Address memAddrLow = interval.low; - Address memAddrHigh = interval.high; + Address memAddrLow = (Address)interval.low; + Address memAddrHigh = (Address)interval.high; #if defined(os_windows) memAddrLow -= b->obj()->cs()->loadAddress(); memAddrHigh -= b->obj()->cs()->loadAddress(); @@ -636,7 +636,7 @@ void BoundValue::MemoryRead(Block* b, int readSize) { if (IsInReadOnlyRegion(memAddrLow, memAddrHigh)) { set values; if (interval.size() <= MAX_TABLE_ENTRY && b->obj()->cs()->isValidAddress(memAddrLow) && b->obj()->cs()->isReadOnly(memAddrLow)) { - for (Address memAddr = memAddrLow ; memAddr <= memAddrHigh; memAddr += interval.stride) { + for (Address memAddr = memAddrLow ; memAddr <= memAddrHigh; memAddr += (Address)interval.stride) { if (!b->obj()->cs()->isValidAddress(memAddr)) { parsing_printf("INVALID ADDRESS %lx\n", memAddr); continue; @@ -1566,7 +1566,7 @@ BoundValue * BoundFact::ApplyRelations(AST::Ptr outAST) { AST::Ptr leftOp = leftChild->child(0); if (leftChild->child(1)->getID() != AST::V_ConstantAST) return NULL; ConstantAST::Ptr baseAST = boost::static_pointer_cast(leftChild->child(1)); - int baseValue = baseAST->val().val; + int64_t baseValue = baseAST->val().val; if (rightChild->child(0)->getID() != AST::V_RoseAST || rightChild->child(1)->getID() != AST::V_ConstantAST) return NULL; RoseAST::Ptr invertAST = boost::static_pointer_cast(rightChild->child(0)); if (invertAST->val().op != ROSEOperation::invertOp) return NULL; diff --git a/parseAPI/src/BoundFactData.h b/parseAPI/src/BoundFactData.h index 62da8b4c78..4a3ab5347b 100644 --- a/parseAPI/src/BoundFactData.h +++ b/parseAPI/src/BoundFactData.h @@ -23,7 +23,7 @@ struct StridedInterval { // stride < 0: bottom (empty set) // stride = 0: represent a constant // stride > 0: represent an interval - int stride; + int64_t stride; int64_t low, high; // Bottom: empty set diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index 28acf33a05..7563e4fa2b 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -386,10 +386,10 @@ AST::Ptr DeepCopyAnAST(AST::Ptr ast) { } else if (ast->getID() == AST::V_BottomAST) { BottomAST::Ptr bottomAST = boost::static_pointer_cast(ast); return BottomAST::create(bottomAST->val()); - } else { - fprintf(stderr, "ast type %d, %s\n", ast->getID(), ast->format().c_str()); - assert(0); } + fprintf(stderr, "ast type %d, %s\n", ast->getID(), ast->format().c_str()); + assert(0); + return nullptr; } AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) { @@ -407,11 +407,11 @@ AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) { Address tableBase = 0; if (roseAST->child(0)->getID() == AST::V_ConstantAST && roseAST->child(1)->getID() == AST::V_VariableAST) { ConstantAST::Ptr constAST = boost::static_pointer_cast(roseAST->child(0)); - tableBase = constAST->val().val; + tableBase = (Address)constAST->val().val; } if (roseAST->child(1)->getID() == AST::V_ConstantAST && roseAST->child(0)->getID() == AST::V_VariableAST) { ConstantAST::Ptr constAST = boost::static_pointer_cast(roseAST->child(1)); - tableBase = constAST->val().val; + tableBase = (Address)constAST->val().val; } if (tableBase) { Architecture arch = b->obj()->cs()->getArch(); diff --git a/parseAPI/src/JumpTablePred.C b/parseAPI/src/JumpTablePred.C index 6b028a645c..ed14c6be58 100644 --- a/parseAPI/src/JumpTablePred.C +++ b/parseAPI/src/JumpTablePred.C @@ -249,8 +249,8 @@ bool JumpTablePred::addNodeCallback(AssignmentPtr ap, set &visi bool JumpTablePred::FillInOutEdges(BoundValue &target, vector >& outEdges) { outEdges.clear(); - Address tableBase = target.interval.low; - Address tableLastEntry = target.interval.high; + Address tableBase = (Address)target.interval.low; + Address tableLastEntry = (Address)target.interval.high; Architecture arch = block->obj()->cs()->getArch(); if (arch == Arch_x86) { tableBase &= 0xffffffff; @@ -278,7 +278,7 @@ bool JumpTablePred::FillInOutEdges(BoundValue &target, } - for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += target.interval.stride) { + for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += (Address)target.interval.stride) { if (!block->obj()->cs()->isValidAddress(tableEntry)) continue; if (!block->obj()->cs()->isReadOnly(tableEntry)) continue; Address targetAddress = 0; diff --git a/parseAPI/src/ProbabilisticParser.C b/parseAPI/src/ProbabilisticParser.C index bb72c24f97..bf3dfded55 100644 --- a/parseAPI/src/ProbabilisticParser.C +++ b/parseAPI/src/ProbabilisticParser.C @@ -495,7 +495,7 @@ bool ProbabilityCalculator::decodeInstruction(DecodeData &data, Address addr) { decodeCache.insert(make_pair(addr, DecodeData(JUNK_OPCODE, 0,0,0))); return false; } - data.len = insn->size(); + data.len = (unsigned short)insn->size(); if (data.len == 0) { decodeCache.insert(make_pair(addr, DecodeData(JUNK_OPCODE, 0,0,0))); return false; From c9a5e4a1c2680a2b0d809d59d1abe07d9abef4a4 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Fri, 1 Jul 2016 17:15:38 -0400 Subject: [PATCH 089/180] suppress proccontrol warnings --- proccontrol/src/handler.C | 4 ++++ proccontrol/src/irpc.C | 4 ++++ proccontrol/src/process.C | 2 +- proccontrol/src/processplat.C | 4 ++++ proccontrol/src/procset.C | 4 ++++ proccontrol/src/x86_process.C | 4 ++++ 6 files changed, 21 insertions(+), 1 deletion(-) diff --git a/proccontrol/src/handler.C b/proccontrol/src/handler.C index 5173f67d1b..c1abc10826 100644 --- a/proccontrol/src/handler.C +++ b/proccontrol/src/handler.C @@ -53,6 +53,10 @@ using namespace std; #include #include +#ifdef _MSC_VER +#pragma warning(disable:4477) +#endif + Handler::Handler(std::string name_) : name(name_) { diff --git a/proccontrol/src/irpc.C b/proccontrol/src/irpc.C index 1a7ac39877..5ceb832c72 100644 --- a/proccontrol/src/irpc.C +++ b/proccontrol/src/irpc.C @@ -48,6 +48,10 @@ #include #include +#ifdef _MSC_VER +#pragma warning(disable:4477) +#endif + using namespace std; unsigned long int_iRPC::next_id; diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C index d231e9ee6d..1522a7577e 100644 --- a/proccontrol/src/process.C +++ b/proccontrol/src/process.C @@ -60,7 +60,7 @@ #include #if defined(os_windows) -#pragma warning(disable:4355) +#pragma warning(disable:4355 4477) #endif using namespace Dyninst; diff --git a/proccontrol/src/processplat.C b/proccontrol/src/processplat.C index a7b3651c14..cd3ec20292 100644 --- a/proccontrol/src/processplat.C +++ b/proccontrol/src/processplat.C @@ -35,6 +35,10 @@ #include "processplat.h" #include "int_event.h" +#ifdef _MSC_VER +#pragma warning(disable:4477) +#endif + using namespace Dyninst; using namespace ProcControlAPI; using namespace std; diff --git a/proccontrol/src/procset.C b/proccontrol/src/procset.C index c760c3679b..64180ac0a6 100644 --- a/proccontrol/src/procset.C +++ b/proccontrol/src/procset.C @@ -52,6 +52,10 @@ #include #include +#ifdef _MSC_VER +#pragma warning(disable:4477) +#endif + using namespace Dyninst; using namespace ProcControlAPI; using namespace std; diff --git a/proccontrol/src/x86_process.C b/proccontrol/src/x86_process.C index 9125f0215d..c292788750 100644 --- a/proccontrol/src/x86_process.C +++ b/proccontrol/src/x86_process.C @@ -32,6 +32,10 @@ #include "int_event.h" #include "Event.h" +#ifdef _MSC_VER +#pragma warning(disable:4477) +#endif + x86_process::x86_process(Dyninst::PID p, std::string e, std::vector a, std::vector envp, std::map f) : int_process(p, e, a, envp, f) { From b6e5b1feaae86a137d4af63d10f4d76067d75263 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 30 Sep 2016 16:18:58 -0500 Subject: [PATCH 090/180] String table now includes an entry at zero for "unknown", so don't subtract from the DWARF file number. --- parseAPI/src/IndirectASTVisitor.C | 2 +- symtabAPI/src/Module.C | 8 +- symtabAPI/src/dwarfWalker.C | 367 +++++++++++++++--------------- 3 files changed, 188 insertions(+), 189 deletions(-) diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index 7563e4fa2b..e29cb1c54c 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -389,7 +389,7 @@ AST::Ptr DeepCopyAnAST(AST::Ptr ast) { } fprintf(stderr, "ast type %d, %s\n", ast->getID(), ast->format().c_str()); assert(0); - return nullptr; + return AST::Ptr(); } AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) { diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 7cc4e2d607..676ed06ccb 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -43,6 +43,10 @@ #include "common/src/pathName.h" #include "common/src/serialize.h" +#if defined(cap_dwarf) +#include "dwarfWalker.h" +#endif + using namespace Dyninst; using namespace Dyninst::SymtabAPI; using namespace std; @@ -156,7 +160,7 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan bool Module::getSourceLines(std::vector &lines, Offset addressInRange) { unsigned int originalSize = lines.size(); - + LineInformation *lineInformation = getLineInformation(); if(!lineInformation) { exec_->parseLineInformation(); @@ -177,7 +181,7 @@ bool Module::getStatements(std::vector &statements) { unsigned initial_size = statements.size(); LineInformation *li = getLineInformation(); - if (!li) + if (!li) { exec_->parseLineInformation(); li = getLineInformation(); diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 2a4cce39aa..2b09cf31ee 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -146,12 +146,12 @@ bool DwarfWalker::parse() { compile_offset = next_cu_header; } } - + if (!fixUnknownMod) return true; dwarf_printf("Fixing types for final module %s\n", fixUnknownMod->fileName().c_str()); - + /* Fix type list. */ typeCollection *moduleTypes = typeCollection::getModTypeCollection(fixUnknownMod); assert(moduleTypes); @@ -160,20 +160,20 @@ bool DwarfWalker::parse() { { typeIter->second->fixupUnknowns(fixUnknownMod); } /* end iteration over types. */ - - /* Fix the types of variables. */ + + /* Fix the types of variables. */ std::string variableName; dyn_hash_map< std::string, Type * >::iterator variableIter = moduleTypes->globalVarsByName.begin(); for (;variableIter!=moduleTypes->globalVarsByName.end();variableIter++) - { - if (variableIter->second->getDataClass() == dataUnknownType && - moduleTypes->findType( variableIter->second->getID() ) != NULL ) + { + if (variableIter->second->getDataClass() == dataUnknownType && + moduleTypes->findType( variableIter->second->getID() ) != NULL ) { - moduleTypes->globalVarsByName[ variableIter->first ] + moduleTypes->globalVarsByName[ variableIter->first ] = moduleTypes->findType( variableIter->second->getID() ); } /* end if data class is unknown but the type exists. */ } /* end iteration over variables. */ - + moduleTypes->setDwarfParsed(); return true; } @@ -182,7 +182,7 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { /* Obtain the module DIE. */ Dwarf_Die moduleDIE; DWARF_FAIL_RET(dwarf_siblingof_b( dbg(), NULL, is_info, &moduleDIE, NULL )); - + /* Make sure we've got the right one. */ Dwarf_Half moduleTag; DWARF_FAIL_RET(dwarf_tag( moduleDIE, & moduleTag, NULL )); @@ -191,7 +191,7 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { && moduleTag != DW_TAG_partial_unit && moduleTag != DW_TAG_type_unit) return false; - + /* Extract the name of this module. */ std::string moduleName; if (!findDieName( moduleDIE, moduleName )) return false; @@ -208,11 +208,11 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { } dwarf_printf("Next DWARF module: %s with DIE %p and tag %d\n", moduleName.c_str(), moduleDIE, moduleTag); - + /* Set the language, if any. */ Dwarf_Attribute languageAttribute; DWARF_ERROR_RET(dwarf_attr( moduleDIE, DW_AT_language, & languageAttribute, NULL )); - + // Set low and high ranges; this can fail, so don't check return addr. setEntry(moduleDIE); @@ -229,7 +229,7 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { setModuleFromName(moduleName); //dwarf_printf("Mapped to Symtab module %s\n", mod()->fileName().c_str()); - + if (!fixUnknownMod) fixUnknownMod = mod(); @@ -259,7 +259,7 @@ void DwarfParseActions::setModuleFromName(std::string moduleName) bool DwarfWalker::buildSrcFiles(Dwarf_Die entry) { Dwarf_Signed cnt = 0; DWARF_ERROR_RET(dwarf_srcfiles(entry, &srcFileList_, &cnt, NULL)); - + srcFiles_.push_back(""); for (unsigned i = 0; i < cnt; ++i) { srcFiles_.push_back(srcFileList_[i]); freeList.push_back(boost::shared_ptr(const_cast(srcFiles_[i]), boost::bind(dwarf_dealloc, dbg(), _1, DW_DLA_STRING))); @@ -275,7 +275,7 @@ bool DwarfWalker::buildSrcFiles(Dwarf_Die entry) { // function, etc. without the Context stack exploding bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { dwarf_printf("PARSE_INT entry, context size %d\n", stack_size()); - // We escape the loop by checking parseSibling() after + // We escape the loop by checking parseSibling() after // parsing this DIE and its children, if any while(1) { ContextGuard cg(*this); @@ -293,12 +293,12 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { e, stack_size(), curFunc(), - // (curFunc() && !curFunc()->getAllMangledNames().empty()) ? + // (curFunc() && !curFunc()->getAllMangledNames().empty()) ? //curFunc()->getAllMangledNames()[0].c_str() : "", curEnclosure()); bool ret = false; - + // BLUEGENE BUG HACK #if defined(os_bg) if (tag() == DW_TAG_base_type || @@ -356,7 +356,7 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { break; case DW_TAG_structure_type: case DW_TAG_union_type: - case DW_TAG_class_type: + case DW_TAG_class_type: ret = parseStructUnionClass(); break; case DW_TAG_enumerator: @@ -367,7 +367,7 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { break; case DW_TAG_const_type: case DW_TAG_packed_type: - case DW_TAG_volatile_type: + case DW_TAG_volatile_type: ret = parseConstPackedVolatile(); break; case DW_TAG_subroutine_type: @@ -375,7 +375,7 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { children of those types. */ case DW_TAG_ptr_to_member_type: case DW_TAG_pointer_type: - case DW_TAG_reference_type: + case DW_TAG_reference_type: ret = parseTypeReferences(); break; case DW_TAG_compile_unit: @@ -399,7 +399,7 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { ret = true; break; } - + dwarf_printf("Finished parsing 0x%lx, ret %d, parseChild %d, parseSibling %d\n", id(), ret, parseChild(), parseSibling()); @@ -424,7 +424,7 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { int status = dwarf_siblingof_b( dbg(), entry(), is_info, & siblingDwarf, NULL ); DWARF_CHECK_RET(status == DW_DLV_ERROR); - + /* Deallocate the entry we just parsed. */ dwarf_dealloc( dbg(), entry(), DW_DLA_DIE ); @@ -434,7 +434,7 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { e = siblingDwarf; } - + dwarf_printf("PARSE_INT exit, context size %d\n", stack_size()); return true; } @@ -472,7 +472,7 @@ bool DwarfWalker::setFunctionFromRange(inline_t func_type) bool set_lowest = false; if (!hasRanges()) { dwarf_printf("(0x%lx) setFunctionFromRange has no ranges, returning false\n", id()); - + return false; } for (range_set_t::iterator i = ranges_begin(); i != ranges_end(); i++) { @@ -554,7 +554,7 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { getReturnType(false, ftype); addFuncToContainer(ftype); dwarf_printf("(0x%lx) parseSubprogram not parsing member function's children\n", id()); - + setParseChild(false); } @@ -595,7 +595,7 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { if (func_type == InlinedFunc) { parseCallsite(); } - + // Get the return type setFuncReturnType(); @@ -605,9 +605,9 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { } // Dwarf outlines some function information. You have the base entry, which contains // address ranges, frame base information, and optionally a "abstract origin" - // or "specification" entry that points to more information. + // or "specification" entry that points to more information. // We want to skip parsing specification or abstract entries until we have - // the base entry and can find/create the corresponding function object. + // the base entry and can find/create the corresponding function object. // Get the frame base if it exists @@ -619,8 +619,8 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { if (hasAbstractOrigin) { dwarf_printf("(0x%lx) Parsing abstract parent\n", id()); if (!parse_int(abstractEntry(), false)) return false; - dwarf_dealloc(dbg(), abstractEntry(), DW_DLA_DIE); - } + dwarf_dealloc(dbg(), abstractEntry(), DW_DLA_DIE); + } // An abstract origin will point to a specification if it exists // This can actually be three-layered, so backchain again bool hasSpecification = false; @@ -668,7 +668,7 @@ bool DwarfWalker::parseHighPCLowPC(Dwarf_Die entry) high = convertDebugOffset(tempHigh); Dwarf_Half form; DWARF_FAIL_RET(dwarf_whatform(hasHigh, &form, NULL)); - + if(form != DW_FORM_addr) { high += low; @@ -676,7 +676,7 @@ bool DwarfWalker::parseHighPCLowPC(Dwarf_Die entry) dwarf_printf("(0x%lx) Lexical block from 0x%lx to 0x%lx\n", id(), low, high); setRange(make_pair(low, high)); return true; - + } @@ -685,14 +685,14 @@ bool DwarfWalker::parseRangeTypes() { clearRanges(); parseHighPCLowPC(entry()); - + Dwarf_Bool hasRanges = false; DWARF_FAIL_RET(dwarf_hasattr(entry(), DW_AT_ranges, &hasRanges, NULL)); if (hasRanges) { Address range_offset; if (!findConstant(DW_AT_ranges, range_offset, entry(), dbg())) return false; - + Dwarf_Ranges *ranges = NULL; Dwarf_Signed ranges_length = 0; DWARF_FAIL_RET(dwarf_get_ranges_a(dbg(), (Dwarf_Off) range_offset, entry(), @@ -719,8 +719,8 @@ bool DwarfWalker::parseRangeTypes() { } } dwarf_ranges_dealloc(dbg(), ranges, ranges_length); - - } + + } return true; } @@ -774,17 +774,17 @@ bool DwarfWalker::parseVariable() { /* Acquire the name, type, and line number. */ /* A variable may occur inside a function, as either static or local. A variable may occur inside a container, as C++ static member. - A variable may not occur in either, as a global. - + A variable may not occur in either, as a global. + For the first two cases, we need the variable's name, its type, its line number, and its offset or address in order to tell Dyninst about it. Dyninst only needs to know the name and type of a global. (Actually, it already knows the names of the globals; we're really just telling it the types.) - + Variables may have two entries, the second, with a _specification, being the only one with the location. */ - + /* If this DIE has a _specification, use that for the rest of our inquiries. */ bool hasSpecification = false; if (!handleSpecification(hasSpecification)) return false; @@ -799,9 +799,9 @@ bool DwarfWalker::parseVariable() { std::vector locs; if (!decodeLocationList(DW_AT_location, NULL, locs)) return false; if (locs.empty()) return true; - + for (unsigned i=0; i locs; if (!decodeLocationList(DW_AT_location, NULL, locs)) return false; if (locs.empty()) { @@ -934,12 +934,12 @@ bool DwarfWalker::parseFormalParam() { } if (!findName(curName())) return false; - /* We can't do anything with anonymous parameters. */ + /* We can't do anything with anonymous parameters. */ if (!nameDefined()) { dwarf_printf("(0x%lx) No name associated with formal, returning\n", id()); - return true; + return true; } - + /* Acquire the parameter's type. */ Type *paramType = NULL; if (!findType(paramType, false)) return false; @@ -995,16 +995,16 @@ bool DwarfWalker::parseBaseType() { we don't bother to try. */ typeScalar * baseType = new typeScalar( type_id(), (unsigned int) size, curName()); assert( baseType != NULL ); - + /* Add the basic type to our collection. */ typeScalar *debug = baseType; baseType = tc()->addOrUpdateType( baseType ); - dwarf_printf("(0x%lx) Created type %p / %s (pre add %p / %s) for id %d, size %d, in TC %p\n", id(), + dwarf_printf("(0x%lx) Created type %p / %s (pre add %p / %s) for id %d, size %d, in TC %p\n", id(), baseType, baseType->getName().c_str(), debug, debug->getName().c_str(), (int) offset(), size, tc()); - + return true; } @@ -1029,10 +1029,10 @@ bool DwarfWalker::parseTypedef() { bool DwarfWalker::parseArray() { dwarf_printf("(0x%lx) Parsing array\n", id()); /* Two words about pgf90 arrays. - - Primus: the PGI extensions to DWARF are documented in + + Primus: the PGI extensions to DWARF are documented in '/p/paradyn/doc/External/manuals/pgf90-dwarf-arrays.txt'. - + Secundus: we ignore DW_AT_PGI_lbase, DW_AT_PGI_loffset, and DW_AT_PGI_lstride, even though libdwarf recognizes them, because our type modelling doesn't allow us to make use of this information. Similarly, in virtually every place where @@ -1043,8 +1043,8 @@ bool DwarfWalker::parseArray() { if (!findName(curName())) return false; - // curName may get overridden by the subrange parsing code. - // TODO: make this part of the context stack. + // curName may get overridden by the subrange parsing code. + // TODO: make this part of the context stack. std::string nameToUse = curName(); Type *elementType = NULL; @@ -1058,35 +1058,35 @@ bool DwarfWalker::parseArray() { push(); - typeArray * baseArrayType = parseMultiDimensionalArray(firstRange, + typeArray * baseArrayType = parseMultiDimensionalArray(firstRange, elementType); pop(); if (!baseArrayType) return false; - + dwarf_dealloc( dbg(), firstRange, DW_DLA_DIE ); - + /* The baseArrayType is an anonymous type with its own typeID. Extract the information and add an array type for this DIE. */ dwarf_printf("(0x%lx) Creating array with base type %s, low bound %ld, high bound %ld, named %s\n", id(), baseArrayType->getBaseType()->getName().c_str(), - baseArrayType->getLow(), + baseArrayType->getLow(), baseArrayType->getHigh(), curName().c_str()); typeArray *arrayType = new typeArray( type_id(), - baseArrayType->getBaseType(), + baseArrayType->getBaseType(), baseArrayType->getLow(), - baseArrayType->getHigh(), - nameToUse); + baseArrayType->getHigh(), + nameToUse); assert( arrayType != NULL ); arrayType = tc()->addOrUpdateType( arrayType ); - + /* Don't parse the children again. */ setParseChild(false); - + return true; } @@ -1148,21 +1148,21 @@ bool DwarfWalker::parseStructUnionClass() { unsigned size; if (!findSize(size)) { - if (isDeclaration) return true; + if (isDeclaration) return true; else return false; } fieldListType * containingType = NULL; switch ( tag() ) { - case DW_TAG_structure_type: + case DW_TAG_structure_type: case DW_TAG_class_type: { typeStruct *ts = new typeStruct( type_id(), curName()); ts->setSize(size); containingType = dynamic_cast(tc()->addOrUpdateType(ts)); break; } - case DW_TAG_union_type: + case DW_TAG_union_type: { typeUnion *tu = new typeUnion( type_id(), curName()); tu->setSize(size); @@ -1207,7 +1207,7 @@ bool DwarfWalker::parseMember() { Correct memberOffset as indicated. Also, memberSize is in bytes from the underlying type, not the # of bits used from it, so correct that as necessary as well. */ - + long int memberSize = memberType->getSize(); // This code changes memberSize, which is then discarded. I'm not sure why... @@ -1252,7 +1252,7 @@ bool DwarfWalker::parseTypeReferences() { Type *typePointedTo = NULL; if (!findType(typePointedTo, true)) return false; - + Type * indirectType = NULL; switch ( tag() ) { case DW_TAG_subroutine_type: @@ -1296,7 +1296,7 @@ bool DwarfWalker::findTag() { bool DwarfWalker::findOffset() { Dwarf_Off dieOffset; DWARF_FAIL_RET(dwarf_dieoffset( entry(), & dieOffset, NULL )); - + setOffset(dieOffset); return true; } @@ -1305,37 +1305,37 @@ bool DwarfWalker::handleAbstractOrigin(bool &isAbstract) { Dwarf_Die absE; dwarf_printf("(0x%lx) Checking for abstract origin\n", id()); - + isAbstract = false; Dwarf_Bool isAbstractOrigin; DWARF_FAIL_RET(dwarf_hasattr(entry(), - DW_AT_abstract_origin, + DW_AT_abstract_origin, &isAbstractOrigin, NULL )); - + if (!isAbstractOrigin) return true; isAbstract = true; dwarf_printf("(0x%lx) abstract_origin is true, looking up reference\n", id()); - + Dwarf_Attribute abstractAttribute; DWARF_FAIL_RET(dwarf_attr( entry(), DW_AT_abstract_origin, & abstractAttribute, NULL )); - + Dwarf_Off abstractOffset; if (!findDieOffset( abstractAttribute, abstractOffset )) return false; - + Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(entry()); DWARF_FAIL_RET(dwarf_offdie_b( dbg(), abstractOffset, is_info, & absE, NULL)); - + dwarf_dealloc( dbg() , abstractAttribute, DW_DLA_ATTR ); - + setAbstractEntry(absE); return true; } bool DwarfWalker::handleSpecification(bool &hasSpec) { - Dwarf_Die specE; + Dwarf_Die specE; dwarf_printf("(0x%lx) Checking for separate specification\n", id()); hasSpec = false; @@ -1346,18 +1346,18 @@ bool DwarfWalker::handleSpecification(bool &hasSpec) { if (!hasSpecification) return true; hasSpec = true; - + dwarf_printf("(0x%lx) Entry has separate specification, retrieving\n", id()); Dwarf_Attribute specAttribute; DWARF_FAIL_RET(dwarf_attr( entry(), DW_AT_specification, & specAttribute, NULL )); - + Dwarf_Off specOffset; if (!findDieOffset( specAttribute, specOffset )) return false; - + Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(entry()); DWARF_FAIL_RET(dwarf_offdie_b( dbg(), specOffset, is_info, & specE, NULL )); - + dwarf_dealloc( dbg(), specAttribute, DW_DLA_ATTR ); setSpecEntry(specE); @@ -1369,7 +1369,7 @@ bool DwarfWalker::findDieName(Dwarf_Die die, std::string &name) { char *cname = NULL; Dwarf_Error error; - int status = dwarf_diename( die, &cname, &error ); + int status = dwarf_diename( die, &cname, &error ); /* Squash errors from unsupported forms, like DW_FORM_GNU_strp_alt. */ if (status == DW_DLV_ERROR) { @@ -1395,7 +1395,7 @@ bool DwarfWalker::findName(std::string &name) { dwarf_printf("(0x%lx) Found name %s\n", id(), name.c_str()); return true; } - + bool DwarfWalker::findFuncName() { dwarf_printf("(0x%lx) Checking for function name\n", id()); @@ -1415,7 +1415,7 @@ bool DwarfWalker::findFuncName() { dwarf_printf("(0x%lx) Found mangled name of %s, using\n", id(), curName().c_str()); dwarf_dealloc( dbg(), linkageNameAttr, DW_DLA_ATTR ); return true; - } + } findDieName( entry(), curName() ); setMangledName(false); @@ -1448,7 +1448,7 @@ bool DwarfWalker::getReturnType(bool hasSpecification, Type *&returnType) { if (hasSpecification) { is_info = dwarf_get_die_infotypes_flag(specEntry()); status = dwarf_attr( specEntry(), DW_AT_type, & typeAttribute, NULL ); - } + } if (!hasSpecification || (status == DW_DLV_NO_ENTRY)) { is_info = dwarf_get_die_infotypes_flag(entry()); status = dwarf_attr( entry(), DW_AT_type, & typeAttribute, NULL ); @@ -1475,7 +1475,7 @@ bool DwarfWalker::addFuncToContainer(Type *returnType) { /* Using the mangled name allows us to distinguish between overridden functions, but confuses the tests. Since Type uses vectors to hold field names, however, duplicate -- demangled names -- are OK. */ - + char * demangledName = P_cplus_demangle( curName().c_str(), isNativeCompiler() ); std::string toUse; @@ -1486,7 +1486,7 @@ bool DwarfWalker::addFuncToContainer(Type *returnType) { else { // Strip everything left of the rightmost ':' off to get rid of the class names toUse = demangledName; - // rfind finds the last occurrence of ':'; add 1 to get past it. + // rfind finds the last occurrence of ':'; add 1 to get past it. size_t offset = toUse.rfind(':'); if (offset != toUse.npos) { toUse = toUse.substr(offset+1); @@ -1579,8 +1579,8 @@ bool DwarfWalker::findAnyType(Dwarf_Attribute typeAttribute, /* The typeOffset forms a module-unique type identifier, so the Type look-ups by it rather than name. */ type = tc()->findOrCreateType( type_id ); - dwarf_printf("(0x%lx) Returning type %p / %s for id 0x%x\n", - id(), + dwarf_printf("(0x%lx) Returning type %p / %s for id 0x%x\n", + id(), type, type->getName().c_str(), type_id); return true; @@ -1599,13 +1599,13 @@ bool DwarfWalker::getLineInformation(Dwarf_Unsigned &variableLineNo, else if (status == DW_DLV_OK) { Dwarf_Unsigned fileNameDeclVal; DWARF_FAIL_RET(dwarf_formudata(fileDeclAttribute, &fileNameDeclVal, NULL)); - dwarf_dealloc( dbg(), fileDeclAttribute, DW_DLA_ATTR ); - if (fileNameDeclVal > srcFiles().size() || fileNameDeclVal <= 0) { + dwarf_dealloc( dbg(), fileDeclAttribute, DW_DLA_ATTR ); + if (fileNameDeclVal >= srcFiles().size() || fileNameDeclVal < 0) { dwarf_printf("Dwarf error reading line index %d from srcFiles of size %lu\n", fileNameDeclVal, srcFiles().size()); return false; } - fileName = srcFiles()[fileNameDeclVal-1]; + fileName = srcFiles()[fileNameDeclVal]; } else { return true; @@ -1615,18 +1615,18 @@ bool DwarfWalker::getLineInformation(Dwarf_Unsigned &variableLineNo, status = dwarf_attr( specEntry(), DW_AT_decl_line, & lineNoAttribute, NULL ); DWARF_CHECK_RET(status == DW_DLV_ERROR); if (status != DW_DLV_OK) return true; - + /* We don't need to tell Dyninst a line number for C++ static variables, so it's OK if there isn't one. */ hasLineNumber = true; DWARF_FAIL_RET(dwarf_formudata( lineNoAttribute, & variableLineNo, NULL )); - dwarf_dealloc( dbg(), lineNoAttribute, DW_DLA_ATTR ); + dwarf_dealloc( dbg(), lineNoAttribute, DW_DLA_ATTR ); return true; } -bool DwarfWalker::decodeLocationList(Dwarf_Half attr, - Address *initialStackValue, +bool DwarfWalker::decodeLocationList(Dwarf_Half attr, + Address *initialStackValue, std::vector &locs) { dwarf_printf("(0x%lx) decodeLocationList for attr %d\n", id(), attr); @@ -1639,7 +1639,7 @@ bool DwarfWalker::decodeLocationList(Dwarf_Half attr, } locs.clear(); - + /* Acquire the location of this formal parameter. */ Dwarf_Attribute locationAttribute; DWARF_FAIL_RET(dwarf_attr( entry(), attr, & locationAttribute, NULL )); @@ -1657,33 +1657,33 @@ bool DwarfWalker::decodeLocationList(Dwarf_Half attr, else if (isExpr) { dwarf_printf("(0x%lx) Decoding expression without location list\n", id()); if (!decodeExpression(locationAttribute, locs)) return false; - } + } else { dwarf_printf("(0x%lx) Decoding loclist location\n", id()); Dwarf_Locdesc **locationList; Dwarf_Signed listLength; int status = dwarf_loclist_n( locationAttribute, & locationList, & listLength, NULL ); - + dwarf_dealloc( dbg(), locationAttribute, DW_DLA_ATTR ); - + if (status != DW_DLV_OK) { - + dwarf_printf("(0x%lx) Failed loclist decode: %d\n", id(), status); return true; } - + dwarf_printf("(0x%lx) location list with %d entries found\n", id(), (int) listLength); - + if (!decodeLocationListForStaticOffsetOrAddress( locationList, - listLength, - locs, + listLength, + locs, initialStackValue)) { deallocateLocationList( locationList, listLength ); return false; } - - + + deallocateLocationList( locationList, listLength ); } @@ -1698,7 +1698,7 @@ bool DwarfWalker::checkForConstantOrExpr(Dwarf_Half attr, constant = false; // Get the form (datatype) for this particular attribute DWARF_FAIL_RET(dwarf_whatform(locationAttribute, &form, NULL)); - + // And see if it's a constant Dwarf_Form_Class formtype = dwarf_get_form_class(version, attr, offset_size, form); dwarf_printf("(0x%lx) Checking for constant, formtype is 0x%x looking for 0x%x\n", id(), formtype, DW_FORM_CLASS_CONSTANT); @@ -1723,12 +1723,7 @@ bool DwarfWalker::findString(Dwarf_Half attr, bool result = findConstant(attr, line_index, entry(), dbg()); if (!result) return false; - if (line_index == 0) { - str = NULL; - return true; - } - line_index--; - if (line_index >= srcFiles().size()) { + if (line_index > srcFiles().size()) { dwarf_printf("Dwarf error reading line index %d from srcFiles of size %lu\n", line_index, srcFiles().size()); return false; @@ -1737,13 +1732,13 @@ bool DwarfWalker::findString(Dwarf_Half attr, return true; } - DWARF_FAIL_RET(dwarf_attr(entry(), attr, &strattr, NULL)); + DWARF_FAIL_RET(dwarf_attr(entry(), attr, &strattr, NULL)); int status = dwarf_whatform(strattr, &form, NULL); if (status != DW_DLV_OK) { dwarf_dealloc(dbg(), strattr, DW_DLA_ATTR); return false; } - + bool result; switch (form) { case DW_FORM_string: { @@ -1754,7 +1749,7 @@ bool DwarfWalker::findString(Dwarf_Half attr, break; } case DW_FORM_block: - case DW_FORM_block1: + case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: { Dwarf_Block *block = NULL; @@ -1788,7 +1783,7 @@ bool DwarfWalker::findConstant(Dwarf_Half attr, Address &value, Dwarf_Die entry, bool ret = findConstantWithForm(d_attr, form, value); dwarf_dealloc(dbg, d_attr, DW_DLA_ATTR); return ret; - + } bool DwarfWalker::findConstantWithForm(Dwarf_Attribute &locationAttribute, @@ -1838,7 +1833,7 @@ bool DwarfWalker::decodeConstantLocation(Dwarf_Attribute &attr, Dwarf_Half form, bool DwarfWalker::constructConstantVariableLocation(Address value, std::vector &locs) { - + VariableLocation loc; loc.stClass = storageAddr; loc.refClass = storageNoRef; @@ -1858,7 +1853,7 @@ bool DwarfWalker::constructConstantVariableLocation(Address value, loc.hiPC = (Address) -1; locs.push_back(loc); } - + return true; } @@ -1872,7 +1867,7 @@ bool DwarfWalker::findSize(unsigned &size) { DWARF_FAIL_RET(dwarf_attr( specEntry(), DW_AT_byte_size, & byteSizeAttr, NULL )); DWARF_FAIL_RET(dwarf_formudata( byteSizeAttr, & byteSize, NULL )); - + dwarf_dealloc( dbg(), byteSizeAttr, DW_DLA_ATTR ); size = (unsigned) byteSize; return true; @@ -1891,7 +1886,7 @@ bool DwarfWalker::findVisibility(visibility_t &visibility) { Dwarf_Unsigned visValue; DWARF_FAIL_RET(dwarf_formudata( visAttr, & visValue, NULL )); - + switch( visValue ) { case DW_ACCESS_public: visibility = visPublic; break; case DW_ACCESS_protected: visibility = visProtected; break; @@ -1900,7 +1895,7 @@ bool DwarfWalker::findVisibility(visibility_t &visibility) { //bperr ( "Uknown visibility, ignoring.\n" ); break; } /* end visibility switch */ - + dwarf_dealloc( dbg(), visAttr, DW_DLA_ATTR ); return true; @@ -1910,7 +1905,7 @@ bool DwarfWalker::findValue(long &value, bool &valid) { Dwarf_Attribute valueAttr; int status = dwarf_attr( entry(), DW_AT_const_value, & valueAttr, NULL ); DWARF_CHECK_RET(status == DW_DLV_ERROR); - + if (status != DW_DLV_OK) { valid = false; return true; @@ -1932,28 +1927,28 @@ bool DwarfWalker::fixBitFields(std::vector &locs, Dwarf_Attribute bitOffset; int status = dwarf_attr( entry(), DW_AT_bit_offset, & bitOffset, NULL ); DWARF_CHECK_RET(status == DW_DLV_ERROR); - - if ( status == DW_DLV_OK && locs.size() ) + + if ( status == DW_DLV_OK && locs.size() ) { Dwarf_Unsigned memberOffset_du = locs[0].frameOffset; - + DWARF_FAIL_RET(dwarf_formudata( bitOffset, &memberOffset_du, NULL )); - + dwarf_dealloc( dbg(), bitOffset, DW_DLA_ATTR ); - + Dwarf_Attribute bitSize; DWARF_FAIL_RET(dwarf_attr( entry(), DW_AT_bit_size, & bitSize, NULL )); - + Dwarf_Unsigned memberSize_du = size; DWARF_FAIL_RET(dwarf_formudata( bitSize, &memberSize_du, NULL )); dwarf_dealloc( dbg(), bitSize, DW_DLA_ATTR ); - + /* If the DW_AT_byte_size field exists, there's some padding. FIXME? We ignore padding for now. (We also don't seem to handle bitfields right in getComponents() anyway...) */ } - else + else { if (locs.size()) locs[0].frameOffset *= 8; @@ -1987,7 +1982,7 @@ void DwarfWalker::removeFortranUnderscore(std::string &name) { if ((lang != lang_Fortran) && (lang != lang_CMFortran) && (lang != lang_Fortran_with_pretty_debug)) return; - + if (name[name.length()-1] == '_') { name = name.substr(0, name.length()-1); } @@ -2014,18 +2009,18 @@ bool DwarfWalker::parseSubrangeAUX(Dwarf_Die entry, default: break; } /* end default lower bound switch */ - + /* Look for the lower bound. */ Dwarf_Attribute lowerBoundAttribute; Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(entry); int status = dwarf_attr( entry, DW_AT_lower_bound, & lowerBoundAttribute, NULL ); DWARF_CHECK_RET(status == DW_DLV_ERROR); - + if ( status == DW_DLV_OK ) { if (!decipherBound(lowerBoundAttribute, is_info, loBound )) return false; dwarf_dealloc( dbg(), lowerBoundAttribute, DW_DLA_ATTR ); } /* end if we found a lower bound. */ - + /* Look for the upper bound. */ Dwarf_Attribute upperBoundAttribute; status = dwarf_attr( entry, DW_AT_upper_bound, & upperBoundAttribute, NULL ); @@ -2040,7 +2035,7 @@ bool DwarfWalker::parseSubrangeAUX(Dwarf_Die entry, if (!decipherBound(upperBoundAttribute, is_info, hiBound )) return false; dwarf_dealloc( dbg(), upperBoundAttribute, DW_DLA_ATTR ); } /* end if we found an upper bound or count. */ - + /* Construct the range type. */ if (!findName(curName())) return false; if (!nameDefined()) { @@ -2056,16 +2051,16 @@ bool DwarfWalker::parseSubrangeAUX(Dwarf_Die entry, if (errno) { low_conv = LONG_MIN; } - + errno = 0; unsigned long hi_conv = strtoul(hiBound.c_str(), NULL, 10); if (errno) { hi_conv = LONG_MAX; - } + } dwarf_printf("(0x%lx) Adding subrange type: id %d, low %ld, high %ld, named %s\n", - id(), type_id, + id(), type_id, low_conv, hi_conv, curName().c_str()); - typeSubrange * rangeType = new typeSubrange( type_id, + typeSubrange * rangeType = new typeSubrange( type_id, 0, low_conv, hi_conv, curName() ); assert( rangeType != NULL ); rangeType = tc()->addOrUpdateType( rangeType ); @@ -2073,7 +2068,7 @@ bool DwarfWalker::parseSubrangeAUX(Dwarf_Die entry, return true; } -typeArray *DwarfWalker::parseMultiDimensionalArray(Dwarf_Die range, +typeArray *DwarfWalker::parseMultiDimensionalArray(Dwarf_Die range, Type * elementType) { char buf[32]; @@ -2100,9 +2095,9 @@ typeArray *DwarfWalker::parseMultiDimensionalArray(Dwarf_Die range, by parseSubRangeDIE(). */ // N.B. I'm going to ignore the type id, and just create an anonymous type here std::string aName = buf; - typeArray* innermostType = new typeArray( elementType, - atoi( loBound.c_str() ), - atoi( hiBound.c_str() ), + typeArray* innermostType = new typeArray( elementType, + atoi( loBound.c_str() ), + atoi( hiBound.c_str() ), aName ); assert( innermostType != NULL ); Type * typ = tc()->addOrUpdateType( innermostType ); @@ -2129,17 +2124,17 @@ bool DwarfWalker::decipherBound(Dwarf_Attribute boundAttribute, Dwarf_Bool is_in { Dwarf_Half boundForm; DWARF_FAIL_RET(dwarf_whatform( boundAttribute, & boundForm, NULL )); - + switch( boundForm ) { case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: - case DW_FORM_udata: + case DW_FORM_udata: { dwarf_printf("(0x%lx) Decoding form %d with formudata\n", id(), boundForm); - + Dwarf_Unsigned constantBound; DWARF_FAIL_RET(dwarf_formudata( boundAttribute, & constantBound, NULL )); char bString[40]; @@ -2152,7 +2147,7 @@ bool DwarfWalker::decipherBound(Dwarf_Attribute boundAttribute, Dwarf_Bool is_in { dwarf_printf("(0x%lx) Decoding form %d with formsdata\n", id(), boundForm); - + Dwarf_Signed constantBound; DWARF_FAIL_RET(dwarf_formsdata( boundAttribute, & constantBound, NULL )); char bString[40]; @@ -2160,44 +2155,44 @@ bool DwarfWalker::decipherBound(Dwarf_Attribute boundAttribute, Dwarf_Bool is_in boundString = bString; return true; } break; - + case DW_FORM_ref_addr: case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: - case DW_FORM_ref_udata: + case DW_FORM_ref_udata: { /* Acquire the referenced DIE. */ Dwarf_Off boundOffset; DWARF_FAIL_RET(dwarf_global_formref( boundAttribute, & boundOffset, NULL )); - + Dwarf_Die boundEntry; DWARF_FAIL_RET(dwarf_offdie_b( dbg(), boundOffset, is_info, & boundEntry, NULL )); - + /* Does it have a name? */ if (findDieName( boundEntry, boundString ) && !boundString.empty()) return true; - + /* Does it describe a nameless constant? */ Dwarf_Attribute constBoundAttribute; int status = dwarf_attr( boundEntry, DW_AT_const_value, & constBoundAttribute, NULL ); DWARF_CHECK_RET(status == DW_DLV_ERROR); - + if ( status == DW_DLV_OK ) { Dwarf_Unsigned constBoundValue; DWARF_FAIL_RET(dwarf_formudata( constBoundAttribute, & constBoundValue, NULL )); - + char bString[40]; sprintf(bString, "%lu", (unsigned long)constBoundValue); boundString = bString; - + dwarf_dealloc( dbg(), boundEntry, DW_DLA_DIE ); dwarf_dealloc( dbg(), constBoundAttribute, DW_DLA_ATTR ); return true; } - + return false; } break; case DW_FORM_block: @@ -2211,7 +2206,7 @@ bool DwarfWalker::decipherBound(Dwarf_Attribute boundAttribute, Dwarf_Bool is_in boundString = "{PGI extension}"; return false; } break; - + default: //bperr ( "Invalid bound form 0x%x\n", boundForm ); boundString = "{invalid bound form}"; @@ -2229,7 +2224,7 @@ bool DwarfWalker::decodeExpression(Dwarf_Attribute &attr, unsigned char *bitstream = (unsigned char *) expr_ptr; // expr_ptr is a pointer to a bytestream. Try to turn it into a Dwarf_Locdesc so - // we can use decodeDwarfExpression. + // we can use decodeDwarfExpression. dwarf_printf("(0x%lx) bitstream for expr has len %d\n", id(), expr_len); for (unsigned i = 0; i < expr_len; ++i) { @@ -2239,7 +2234,7 @@ bool DwarfWalker::decodeExpression(Dwarf_Attribute &attr, Dwarf_Signed cnt; Dwarf_Locdesc *descs; - DWARF_FAIL_RET(dwarf_loclist_from_expr_a(dbg(), expr_ptr, expr_len, addr_size, + DWARF_FAIL_RET(dwarf_loclist_from_expr_a(dbg(), expr_ptr, expr_len, addr_size, &descs, &cnt, NULL)); assert(cnt == 1); @@ -2248,8 +2243,8 @@ bool DwarfWalker::decodeExpression(Dwarf_Attribute &attr, return ret; } -bool DwarfWalker::decodeLocationListForStaticOffsetOrAddress( Dwarf_Locdesc **locationList, - Dwarf_Signed listLength, +bool DwarfWalker::decodeLocationListForStaticOffsetOrAddress( Dwarf_Locdesc **locationList, + Dwarf_Signed listLength, std::vector& locs, Address * initialStackValue) { @@ -2276,15 +2271,15 @@ bool DwarfWalker::decodeLocationListForStaticOffsetOrAddress( Dwarf_Locdesc **lo /* We now parse the complete location list for variables and parameters within a * function. We still ignore the location list defined for DW_AT_frame_base of the * function as the frame pointer is readily available on all platforms(except for IA64) - * May be we would need to parse the location list for IA64 functions to store the - * register numbers and offsets and use it based on the pc value. + * May be we would need to parse the location list for IA64 functions to store the + * register numbers and offsets and use it based on the pc value. */ uint64_t max_addr = (addr_size == 4) ? 0xffffffff : 0xffffffffffffffff; Address base = modLow; - + for (unsigned locIndex = 0 ; locIndex < listLength; locIndex++) { - + /* There is only one location. */ Dwarf_Locdesc *location = locationList[locIndex]; @@ -2294,16 +2289,16 @@ bool DwarfWalker::decodeLocationListForStaticOffsetOrAddress( Dwarf_Locdesc **lo loc.refClass = storageNoRef; // If location == 0..-1, it's "unset" and we keep the big range unless - // we're in a lexical block construct. - // - dwarf_printf("(0x%lx) Decoding entry %d of %d over range 0x%lx - 0x%lx, mod 0x%lx - 0x%lx, base 0x%lx\n", + // we're in a lexical block construct. + // + dwarf_printf("(0x%lx) Decoding entry %d of %d over range 0x%lx - 0x%lx, mod 0x%lx - 0x%lx, base 0x%lx\n", id(), locIndex+1, (int) listLength, (long) location->ld_lopc, (long) location->ld_hipc, modLow, modHigh, base); if (location->ld_lopc == max_addr) { - //This is a base address selection entry, which changes the base address of + //This is a base address selection entry, which changes the base address of // subsequent entries base = location->ld_hipc; continue; @@ -2320,7 +2315,7 @@ bool DwarfWalker::decodeLocationListForStaticOffsetOrAddress( Dwarf_Locdesc **lo if (location->ld_lopc == 0 && location->ld_hipc == (Dwarf_Addr) ~0) { // Unset low and high. Use the lexical block info if present, otherwise - // pass through. + // pass through. if (hasRanges()) { dwarf_printf("(0x%lx) Using lexical range\n", id()); for (range_set_t::iterator i = ranges_begin(); i != ranges_end(); i++) { @@ -2328,17 +2323,17 @@ bool DwarfWalker::decodeLocationListForStaticOffsetOrAddress( Dwarf_Locdesc **lo loc.lowPC = range.first; loc.hiPC = range.second; - dwarf_printf("(0x%lx) Variable valid over range 0x%lx to 0x%lx\n", + dwarf_printf("(0x%lx) Variable valid over range 0x%lx to 0x%lx\n", id(), loc.lowPC, loc.hiPC); locs.push_back(loc); } } else { - dwarf_printf("(0x%lx) Using open location range\n", id()); + dwarf_printf("(0x%lx) Using open location range\n", id()); loc.lowPC = location->ld_lopc; loc.hiPC = location->ld_hipc; - dwarf_printf("(0x%lx) Variable valid over range 0x%lx to 0x%lx\n", + dwarf_printf("(0x%lx) Variable valid over range 0x%lx to 0x%lx\n", id(), loc.lowPC, loc.hiPC); locs.push_back(loc); } @@ -2348,19 +2343,19 @@ bool DwarfWalker::decodeLocationListForStaticOffsetOrAddress( Dwarf_Locdesc **lo loc.lowPC = location->ld_lopc + base; loc.hiPC = location->ld_hipc + base; - dwarf_printf("(0x%lx) Variable valid over range 0x%lx to 0x%lx\n", + dwarf_printf("(0x%lx) Variable valid over range 0x%lx to 0x%lx\n", id(), loc.lowPC, loc.hiPC); locs.push_back(loc); } } - + /* decode successful */ return !locs.empty(); } /* end decodeLocationListForStaticOffsetOrAddress() */ -void DwarfWalker::deallocateLocationList( Dwarf_Locdesc ** locationList, - Dwarf_Signed listLength ) +void DwarfWalker::deallocateLocationList( Dwarf_Locdesc ** locationList, + Dwarf_Signed listLength ) { for( int i = 0; i < listLength; i++ ) { dwarf_dealloc( dbg(), locationList[i]->ld_s, DW_DLA_LOC_BLOCK ); @@ -2390,8 +2385,8 @@ void DwarfParseActions::pop() { void DwarfParseActions::setFunc(FunctionBase *f) { // Bug workaround; if we're setting a function, ignore - // any preceding lexical information since we probably - // nested. + // any preceding lexical information since we probably + // nested. c.top().func = f; } From 6ab6a56c1621794f1f6ec48bd71f4ec7027813e9 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 30 Sep 2016 16:48:31 -0500 Subject: [PATCH 091/180] Replace all object-elf arch_foo defines with dynamic architecture detection. --- symtabAPI/src/Object-elf.C | 809 +++++++++++++++++++------------------ 1 file changed, 406 insertions(+), 403 deletions(-) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 804ee2d234..b6bfcce39c 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -621,12 +621,19 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, // in section. if (!scn.isFromDebugFile()) { allRegionHdrs.push_back(&scn); + Elf_X_Data data = scn.get_data(); + if(strcmp(name, OPD_NAME) == 0) + { + data.d_type(ELF_T_XWORD); + data.xlatetom(elfHdr->e_endian() ? ELFDATA2MSB : ELFDATA2LSB); + } if(scn.sh_flags() & SHF_ALLOC) { // .bss, etc. have a disk size of 0 unsigned long diskSize = (scn.sh_type() == SHT_NOBITS) ? 0 : scn.sh_size(); + Region *reg = new Region(i, name, scn.sh_addr(), diskSize, scn.sh_addr(), scn.sh_size(), - (mem_image()+scn.sh_offset()), + ((char*)data.d_buf()), getRegionPerms(scn.sh_flags()), getRegionType(scn.sh_type(), scn.sh_flags(), @@ -638,7 +645,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, } else { Region *reg = new Region(i, name, scn.sh_addr(), scn.sh_size(), 0, 0, - (mem_image()+scn.sh_offset()), + ((char*)data.d_buf()), getRegionPerms(scn.sh_flags()), getRegionType(scn.sh_type(), scn.sh_flags(), @@ -762,74 +769,63 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, plt_scnp = scnp; plt_addr_ = scn.sh_addr(); plt_size_ = scn.sh_size(); -#if defined(arch_x86) || defined(arch_x86_64) - // - // On x86, the GNU linker purposefully sets the PLT - // table entry size to an incorrect value to be - // compatible with the UnixWare linker. (See the comment - // in the elf_i386_finish_dynamic_sections function of - // the BFD library.) The GNU linker sets this value to 4, - // when it should be 16. - // - // I see no good way to determine this value from the - // ELF section header information. We can either (a) hard-code - // the value that is used in the BFD library, or (b) compute - // it by dividing the size of the PLT by the number of entries - // we think should be in the PLT. I'm not certain, but I - // believe the PLT and the .rel.plt section should have the - // same number of "real" entries (the x86 PLT has one extra entry - // at the beginning). - // - // This code is applicable to any x86 system that uses the - // GNU linker. We currently only support Linux on x86 - if - // we start supporting some other x86 OS that uses the GNU - // linker in the future, it should be enabled for that platform as well. - // Note that this problem does not affect the non-x86 platforms - // that might use the GNU linker. For example, programs linked - // with gld on SPARC Solaris have the correct PLT entry size. - // - // Another potential headache in the future is if we support - // some other x86 platform that has both the GNU linker and - // some other linker. (Does BSD fall into this category?) - // If the two linkers set the entry size differently, we may - // need to re-evaluate this code. - // - //plt_entry_size_ = plt_size_ / ((rel_plt_size_ / rel_plt_entry_size_) + 1); - plt_entry_size_ = 16; - assert( plt_entry_size_ == 16 ); -#else - plt_entry_size_ = scn.sh_entsize(); - - // X86-64: if we're on a 32-bit binary then set the PLT entry size to 16 - // as above -#if defined(arch_x86_64) - if (addressWidth_nbytes == 4) { - plt_entry_size_ = 16; - assert( plt_entry_size_ == 16 ); - } - else { - assert(addressWidth_nbytes == 8); - } -#endif - - -#if defined (ppc32_linux) || defined(ppc32_bgp) - if (scn.sh_flags() & SHF_EXECINSTR) { - // Old style executable PLT - if (!plt_entry_size_) - plt_entry_size_ = 8; - else { - if (plt_entry_size_ != 8) - create_printf("%s[%d]: weird plt_entry_size_ is %d, not 8\n", - FILE__, __LINE__, plt_entry_size_); - } + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { + // + // On x86, the GNU linker purposefully sets the PLT + // table entry size to an incorrect value to be + // compatible with the UnixWare linker. (See the comment + // in the elf_i386_finish_dynamic_sections function of + // the BFD library.) The GNU linker sets this value to 4, + // when it should be 16. + // + // I see no good way to determine this value from the + // ELF section header information. We can either (a) hard-code + // the value that is used in the BFD library, or (b) compute + // it by dividing the size of the PLT by the number of entries + // we think should be in the PLT. I'm not certain, but I + // believe the PLT and the .rel.plt section should have the + // same number of "real" entries (the x86 PLT has one extra entry + // at the beginning). + // + // This code is applicable to any x86 system that uses the + // GNU linker. We currently only support Linux on x86 - if + // we start supporting some other x86 OS that uses the GNU + // linker in the future, it should be enabled for that platform as well. + // Note that this problem does not affect the non-x86 platforms + // that might use the GNU linker. For example, programs linked + // with gld on SPARC Solaris have the correct PLT entry size. + // + // Another potential headache in the future is if we support + // some other x86 platform that has both the GNU linker and + // some other linker. (Does BSD fall into this category?) + // If the two linkers set the entry size differently, we may + // need to re-evaluate this code. + // + //plt_entry_size_ = plt_size_ / ((rel_plt_size_ / rel_plt_entry_size_) + 1); + plt_entry_size_ = 16; + assert(plt_entry_size_ == 16); + } + else + { + plt_entry_size_ = scn.sh_entsize(); + if(getArch() == Dyninst::Arch_ppc32) + { + if (scn.sh_flags() & SHF_EXECINSTR) { + // Old style executable PLT + if (!plt_entry_size_) + plt_entry_size_ = 8; + else { + if (plt_entry_size_ != 8) + create_printf("%s[%d]: weird plt_entry_size_ is %d, not 8\n", + FILE__, __LINE__, plt_entry_size_); + } - } else { - // New style secure PLT - plt_entry_size_ = 16; - } -#endif -#endif + } else { + // New style secure PLT + plt_entry_size_ = 16; + } + } + } } else if (strcmp(name, COMMENT_NAME) == 0) { /* comment section is a sequence of NULL-terminated strings. We want to concatenate them and search for BGP to determine @@ -1089,349 +1085,352 @@ bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, if( reldata.isValid() && symdata.isValid() && strdata.isValid() ) { Offset next_plt_entry_addr = plt_addr_; - -#if defined(arch_x86) || defined(arch_x86_64) + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) + { next_plt_entry_addr += plt_entry_size_; // 1st PLT entry is special - -#elif defined (ppc32_linux) || defined(ppc32_bgp) + } + else if(getArch()==Dyninst::Arch_ppc32) + { bool extraStubs = false; - // Sanity check. - if (!plt_entry_size_) { - create_printf("%s[%d]: FIXME: plt_entry_size not established\n", FILE__, __LINE__); - plt_entry_size_ = 8; - } - - if (plt_entry_size_ == 8) { - // Old style executable PLT section - next_plt_entry_addr += 9*plt_entry_size_; // 1st 9 PLT entries are special - - } else if (plt_entry_size_ == 16) { - // New style secure PLT - Region *plt = NULL, *relplt = NULL, *dynamic = NULL, - *got = NULL, *glink = NULL; - unsigned int glink_addr = 0; - unsigned int stub_addr = 0; - - // Find the GLINK section. See ppc_elf_get_synthetic_symtab() in - // bfd/elf32-ppc.c of GNU's binutils for more information. - - for (unsigned iter = 0; iter < regions_.size(); ++iter) { - std::string name = regions_[iter]->getRegionName(); - if (name == PLT_NAME) plt = regions_[iter]; - else if (name == REL_PLT_NAME) relplt = regions_[iter]; - else if (name == DYNAMIC_NAME) dynamic = regions_[iter]; - else if (name == GOT_NAME) got = regions_[iter]; - } - - // Rely on .dynamic section for prelinked binaries. - if (dynamic != NULL) { - Elf32_Dyn *dyn = (Elf32_Dyn *)dynamic->getPtrToRawData(); - unsigned int count = dynamic->getMemSize() / sizeof(Elf32_Dyn); - - for (unsigned int i = 0; i < count; ++i) { - // Use DT_LOPROC instead of DT_PPC_GOT to circumvent problems - // caused by early versions of libelf where DT_PPC_GOT has - // yet to be defined. - if (dyn[i].d_tag == DT_LOPROC) { - unsigned int g_o_t = dyn[i].d_un.d_val; - if (got != NULL) { - unsigned char *data = - (unsigned char *)got->getPtrToRawData(); - glink_addr = *(unsigned int *) - (data + (g_o_t - got->getMemOffset() + 4)); - break; - } - } - } - } + // Sanity check. + if (!plt_entry_size_) { + create_printf("%s[%d]: FIXME: plt_entry_size not established\n", FILE__, __LINE__); + plt_entry_size_ = 8; + } - // Otherwise, first entry in .plt section holds the glink address - if (glink_addr == 0) { - unsigned char *data = (unsigned char *)plt->getPtrToRawData(); - glink_addr = *(unsigned int *)(data); - } + if (plt_entry_size_ == 8) { + // Old style executable PLT section + next_plt_entry_addr += 9*plt_entry_size_; // 1st 9 PLT entries are special + + } else if (plt_entry_size_ == 16) { + // New style secure PLT + Region *plt = NULL, *relplt = NULL, *dynamic = NULL, + *got = NULL, *glink = NULL; + unsigned int glink_addr = 0; + unsigned int stub_addr = 0; + + // Find the GLINK section. See ppc_elf_get_synthetic_symtab() in + // bfd/elf32-ppc.c of GNU's binutils for more information. + + for (unsigned iter = 0; iter < regions_.size(); ++iter) { + std::string name = regions_[iter]->getRegionName(); + if (name == PLT_NAME) plt = regions_[iter]; + else if (name == REL_PLT_NAME) relplt = regions_[iter]; + else if (name == DYNAMIC_NAME) dynamic = regions_[iter]; + else if (name == GOT_NAME) got = regions_[iter]; + } - // Search for region that contains glink address - for (unsigned iter = 0; iter < regions_.size(); ++iter) { - unsigned int start = regions_[iter]->getMemOffset(); - unsigned int end = start + regions_[iter]->getMemSize(); - if (start <= glink_addr && glink_addr < end) { - glink = regions_[iter]; - break; - } - } + // Rely on .dynamic section for prelinked binaries. + if (dynamic != NULL) { + Elf32_Dyn *dyn = (Elf32_Dyn *)dynamic->getPtrToRawData(); + unsigned int count = dynamic->getMemSize() / sizeof(Elf32_Dyn); + + for (unsigned int i = 0; i < count; ++i) { + // Use DT_LOPROC instead of DT_PPC_GOT to circumvent problems + // caused by early versions of libelf where DT_PPC_GOT has + // yet to be defined. + if (dyn[i].d_tag == DT_LOPROC) { + unsigned int g_o_t = dyn[i].d_un.d_val; + if (got != NULL) { + unsigned char *data = + (unsigned char *)got->getPtrToRawData(); + glink_addr = *(unsigned int *) + (data + (g_o_t - got->getMemOffset() + 4)); + break; + } + } + } + } - if (!glink) { - return false; - } + // Otherwise, first entry in .plt section holds the glink address + if (glink_addr == 0) { + unsigned char *data = (unsigned char *)plt->getPtrToRawData(); + glink_addr = *(unsigned int *)(data); + } - // Find PLT function stubs. They preceed the glink section. - stub_addr = glink_addr - (rel_plt_size_/rel_plt_entry_size_) * 16; - - const unsigned int LWZ_11_30 = 0x817e0000; - const unsigned int ADDIS_11_30 = 0x3d7e0000; - const unsigned int LWZ_11_11 = 0x816b0000; - const unsigned int MTCTR_11 = 0x7d6903a6; - const unsigned int BCTR = 0x4e800420; - - unsigned char *sec_data = (unsigned char *)glink->getPtrToRawData(); - unsigned int *insn = (unsigned int *) - (sec_data + (stub_addr - glink->getMemOffset())); - - // Keep moving pointer back if more -fPIC stubs are found. - while (sec_data < (unsigned char *)insn) { - unsigned int *back = insn - 4; - - if (( (back[0] & 0xffff0000) == LWZ_11_30 - && back[1] == MTCTR_11 - && back[2] == BCTR) - - || ( (back[0] & 0xffff0000) == ADDIS_11_30 - && (back[1] & 0xffff0000) == LWZ_11_11 - && back[2] == MTCTR_11 - && back[3] == BCTR)) - { - extraStubs = true; - stub_addr -= 16; - insn = back; - } else { - break; - } - } + // Search for region that contains glink address + for (unsigned iter = 0; iter < regions_.size(); ++iter) { + unsigned int start = regions_[iter]->getMemOffset(); + unsigned int end = start + regions_[iter]->getMemSize(); + if (start <= glink_addr && glink_addr < end) { + glink = regions_[iter]; + break; + } + } - // Okay, this is where things get hairy. If we have a one to one - // relationship between the glink stubs and plt entries (meaning - // extraStubs == false), then we can generate our relocationEntry - // objects normally below. - - // However, if we have extra glink stubs, then we must generate - // relocations with unknown destinations for *all* stubs. Then, - // we use the loop below to store additional information about - // the data plt entry keyed by plt entry address. - - // Finally, if a symbol with any of the following forms: - // [hex_addr].got2.plt_pic32.[sym_name] - // [hex_addr].plt_pic32.[sym_name] - // - // matches the glink stub address, then stub symbols exist and we - // can rely on these tell us where the stub will eventually go. - - if (extraStubs == true) { - std::string name; - relocationEntry re; - - while (stub_addr < glink_addr) { - if (symsByOffset_.find(stub_addr) != symsByOffset_.end()) { - name = (symsByOffset_[stub_addr])[0]->getMangledName(); - name = name.substr( name.rfind("plt_pic32.") + 10 ); - } - - if (!name.empty()) { - re = relocationEntry( stub_addr, 0, name, NULL, 0 ); - } else { - re = relocationEntry( stub_addr, 0, "@plt", NULL, 0 ); - } - fbt_.push_back(re); - stub_addr += 16; - } - - // Now prepare to iterate over plt below. - next_plt_entry_addr = plt_addr_; - plt_entry_size_ = 4; - - } else { - next_plt_entry_addr = stub_addr; - } + if (!glink) { + return false; + } - } else { - create_printf("ERROR: Can't handle %d PLT entry size\n", - plt_entry_size_); - return false; - } + // Find PLT function stubs. They preceed the glink section. + stub_addr = glink_addr - (rel_plt_size_/rel_plt_entry_size_) * 16; - // actually this is just fudged to make the offset value 72, which is what binutils uses - // Note that binutils makes the distinction between PLT_SLOT_SIZE (8), - // and PLT_ENTRY_SIZE (12). PLT_SLOT_SIZE seems to be what we want, even though we also - // have PLT_INITIAL_ENTRY_SIZE (72) - // see binutils/bfd/elf32-ppc.c/h if more info is needed - //next_plt_entry_addr += 72; // 1st 6 PLT entries art special - -#elif defined(arch_power) && defined(arch_64bit) && defined(os_linux) - // Unlike PPC32 Linux, we don't have a deterministic way of finding - // PPC64 Linux linker stubs. So, we'll wait until the CFG is built - // inside Dyninst, and code read at that point. To find them at this - // point would require a scan of the entire .text section. - // - // If we're lucky, symbols may exist for these linker stubs. They will - // come in the following forms: - // [hex_addr].plt_call.[sym_name] - // [hex_addr].plt_branch.[sym_name] - // [hex_addr].long_branch.[sym_name] - // [hex_addr].plt_branch_r2off.[sym_name] - // [hex_addr].long_branch_r2off.[sym_name] - // - // Again unlike PPC32 above, we have no glink stub address to compare - // against, so we must search through all symbols to find these names. - // - - // First, build a map of the .rela.plt symbol name -> .rela.plt offset: - dyn_hash_map plt_rel_map; - - // I'm not a fan of code duplication, but merging this into the - // loop below would be ugly and difficult to maintain. - Elf_X_Sym _sym = symdata.get_sym(); - Elf_X_Rel _rel = reldata.get_rel(); - Elf_X_Rela _rela = reldata.get_rela(); - const char *_strs = strdata.get_string(); - - for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { - long _offset; - long _index; - - switch (reldata.d_type()) { - case ELF_T_REL: - _offset = _rel.r_offset(i); - _index = _rel.R_SYM(i); - break; - - case ELF_T_RELA: - _offset = _rela.r_offset(i); - _index = _rela.R_SYM(i); - break; - - default: - // We should never reach this case. - return false; - }; - - std::string _name = &_strs[ _sym.st_name(_index) ]; - // I'm interested to see if this assert will ever fail. - assert(_name.length()); - - plt_rel_map[_name] = _offset; - } - // End code duplication. - - dyn_hash_map >::iterator iter; - for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { - std::string name = iter->first; - if (name.length() > 8) { - if (name.substr(8, 10) == ".plt_call.") - name = name.substr(8 + 10); - else if (name.substr(8, 12) == ".plt_branch.") - name = name.substr(8 + 12); - else if (name.substr(8, 13) == ".long_branch.") - name = name.substr(8 + 13); - else if (name.substr(8, 18) == ".plt_branch_r2off.") - name = name.substr(8 + 18); - else if (name.substr(8, 19) == ".long_branch_r2off.") - name = name.substr(8 + 19); - else - continue; - - // Remove possible trailing addend value. - std::string::size_type pos = name.rfind('+'); - if (pos != std::string::npos) name.erase(pos); - - // Remove possible version number. - pos = name.find('@'); - if (pos != std::string::npos) name.erase(pos); - - // Find the dynamic symbol this linker stub branches to. - Symbol *targ_sym = NULL; - if (symbols_.find(name) != symbols_.end()) - for (unsigned i = 0; i < symbols_[name].size(); ++i) - if ( (symbols_[name])[i]->isInDynSymtab()) - targ_sym = (symbols_[name])[i]; - - // If a corresponding target symbol cannot be found for a - // named linker stub, then ignore it. We'll find it during - // parsing. - if (!targ_sym) continue; - - if (iter->second.size() != 1) - continue; - dyn_hash_map::iterator pltrel_iter = plt_rel_map.find(name); - if (pltrel_iter == plt_rel_map.end()) - continue; - - Symbol *stub_sym = iter->second[0]; - relocationEntry re(stub_sym->getOffset(), - pltrel_iter->second, - name, - targ_sym); - fbt_.push_back(re); - } - } + const unsigned int LWZ_11_30 = 0x817e0000; + const unsigned int ADDIS_11_30 = 0x3d7e0000; + const unsigned int LWZ_11_11 = 0x816b0000; + const unsigned int MTCTR_11 = 0x7d6903a6; + const unsigned int BCTR = 0x4e800420; - // 1st plt entry is special. - next_plt_entry_addr += plt_entry_size_; + unsigned char *sec_data = (unsigned char *)glink->getPtrToRawData(); + unsigned int *insn = (unsigned int *) + (sec_data + (stub_addr - glink->getMemOffset())); -#elif defined(arch_aarch64) - // For ARM, the first entry should be skipped, - // but the first entry is in double size - next_plt_entry_addr += 2 * plt_entry_size_; -#else - next_plt_entry_addr += 4*(plt_entry_size_); //1st 4 entries are special -#endif + // Keep moving pointer back if more -fPIC stubs are found. + while (sec_data < (unsigned char *)insn) { + unsigned int *back = insn - 4; - Elf_X_Sym sym = symdata.get_sym(); - Elf_X_Rel rel = reldata.get_rel(); - Elf_X_Rela rela = reldata.get_rela(); - const char *strs = strdata.get_string(); - - if (sym.isValid() && (rel.isValid() || rela.isValid()) && strs) { - - // Sometimes, PPC32 Linux may use this loop to update fbt entries. - // Should stay -1 for all other platforms. See notes above. - int fbt_iter = -1; - if (fbt_.size() > 0 && !fbt_[0].rel_addr() && fbt_[0].name() != "@plt") - fbt_iter = 0; - - for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { - long offset; - long addend; - long index; - unsigned long type; - Region::RegionType rtype; - - switch (reldata.d_type()) { - case ELF_T_REL: - offset = rel.r_offset(i); - addend = 0; - index = rel.R_SYM(i); - type = rel.R_TYPE(i); - rtype = Region::RT_REL; - break; + if (( (back[0] & 0xffff0000) == LWZ_11_30 + && back[1] == MTCTR_11 + && back[2] == BCTR) - case ELF_T_RELA: - offset = rela.r_offset(i); - addend = rela.r_addend(i); - index = rela.R_SYM(i); - type = rela.R_TYPE(i); - rtype = Region::RT_RELA; - break; + || ( (back[0] & 0xffff0000) == ADDIS_11_30 + && (back[1] & 0xffff0000) == LWZ_11_11 + && back[2] == MTCTR_11 + && back[3] == BCTR)) + { + extraStubs = true; + stub_addr -= 16; + insn = back; + } else { + break; + } + } - default: - // We should never reach this case. - return false; - }; + // Okay, this is where things get hairy. If we have a one to one + // relationship between the glink stubs and plt entries (meaning + // extraStubs == false), then we can generate our relocationEntry + // objects normally below. + + // However, if we have extra glink stubs, then we must generate + // relocations with unknown destinations for *all* stubs. Then, + // we use the loop below to store additional information about + // the data plt entry keyed by plt entry address. + + // Finally, if a symbol with any of the following forms: + // [hex_addr].got2.plt_pic32.[sym_name] + // [hex_addr].plt_pic32.[sym_name] + // + // matches the glink stub address, then stub symbols exist and we + // can rely on these tell us where the stub will eventually go. + + if (extraStubs == true) { + std::string name; + relocationEntry re; + + while (stub_addr < glink_addr) { + if (symsByOffset_.find(stub_addr) != symsByOffset_.end()) { + name = (symsByOffset_[stub_addr])[0]->getMangledName(); + name = name.substr( name.rfind("plt_pic32.") + 10 ); + } - std::string targ_name = &strs[ sym.st_name(index) ]; - vector dynsym_list; - if (symbols_.find(targ_name) != symbols_.end()) - { - vector &syms = symbols_[&strs[ sym.st_name(index)]]; - for (vector::iterator i = syms.begin(); i != syms.end(); i++) { - if (!(*i)->isInDynSymtab()) - continue; - dynsym_list.push_back(*i); + if (!name.empty()) { + re = relocationEntry( stub_addr, 0, name, NULL, 0 ); + } else { + re = relocationEntry( stub_addr, 0, "@plt", NULL, 0 ); } + fbt_.push_back(re); + stub_addr += 16; } - else { - dynsym_list.clear(); + + // Now prepare to iterate over plt below. + next_plt_entry_addr = plt_addr_; + plt_entry_size_ = 4; + + } else { + next_plt_entry_addr = stub_addr; + } + + } else { + create_printf("ERROR: Can't handle %d PLT entry size\n", + plt_entry_size_); + return false; + } + + // actually this is just fudged to make the offset value 72, which is what binutils uses + // Note that binutils makes the distinction between PLT_SLOT_SIZE (8), + // and PLT_ENTRY_SIZE (12). PLT_SLOT_SIZE seems to be what we want, even though we also + // have PLT_INITIAL_ENTRY_SIZE (72) + // see binutils/bfd/elf32-ppc.c/h if more info is needed + //next_plt_entry_addr += 72; // 1st 6 PLT entries art special + + + } else if(getArch() == Dyninst::Arch_ppc64) + { + // Unlike PPC32 Linux, we don't have a deterministic way of finding + // PPC64 Linux linker stubs. So, we'll wait until the CFG is built + // inside Dyninst, and code read at that point. To find them at this + // point would require a scan of the entire .text section. + // + // If we're lucky, symbols may exist for these linker stubs. They will + // come in the following forms: + // [hex_addr].plt_call.[sym_name] + // [hex_addr].plt_branch.[sym_name] + // [hex_addr].long_branch.[sym_name] + // [hex_addr].plt_branch_r2off.[sym_name] + // [hex_addr].long_branch_r2off.[sym_name] + // + // Again unlike PPC32 above, we have no glink stub address to compare + // against, so we must search through all symbols to find these names. + // + + // First, build a map of the .rela.plt symbol name -> .rela.plt offset: + dyn_hash_map plt_rel_map; + + // I'm not a fan of code duplication, but merging this into the + // loop below would be ugly and difficult to maintain. + Elf_X_Sym _sym = symdata.get_sym(); + Elf_X_Rel _rel = reldata.get_rel(); + Elf_X_Rela _rela = reldata.get_rela(); + const char *_strs = strdata.get_string(); + + for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { + long _offset; + long _index; + + switch (reldata.d_type()) { + case ELF_T_REL: + _offset = _rel.r_offset(i); + _index = _rel.R_SYM(i); + break; + + case ELF_T_RELA: + _offset = _rela.r_offset(i); + _index = _rela.R_SYM(i); + break; + + default: + // We should never reach this case. + return false; + }; + + std::string _name = &_strs[ _sym.st_name(_index) ]; + // I'm interested to see if this assert will ever fail. + assert(_name.length()); + + plt_rel_map[_name] = _offset; + } + // End code duplication. + + dyn_hash_map >::iterator iter; + for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { + std::string name = iter->first; + if (name.length() > 8) { + if (name.substr(8, 10) == ".plt_call.") + name = name.substr(8 + 10); + else if (name.substr(8, 12) == ".plt_branch.") + name = name.substr(8 + 12); + else if (name.substr(8, 13) == ".long_branch.") + name = name.substr(8 + 13); + else if (name.substr(8, 18) == ".plt_branch_r2off.") + name = name.substr(8 + 18); + else if (name.substr(8, 19) == ".long_branch_r2off.") + name = name.substr(8 + 19); + else + continue; + + // Remove possible trailing addend value. + std::string::size_type pos = name.rfind('+'); + if (pos != std::string::npos) name.erase(pos); + + // Remove possible version number. + pos = name.find('@'); + if (pos != std::string::npos) name.erase(pos); + + // Find the dynamic symbol this linker stub branches to. + Symbol *targ_sym = NULL; + if (symbols_.find(name) != symbols_.end()) + for (unsigned i = 0; i < symbols_[name].size(); ++i) + if ( (symbols_[name])[i]->isInDynSymtab()) + targ_sym = (symbols_[name])[i]; + + // If a corresponding target symbol cannot be found for a + // named linker stub, then ignore it. We'll find it during + // parsing. + if (!targ_sym) continue; + + if (iter->second.size() != 1) + continue; + dyn_hash_map::iterator pltrel_iter = plt_rel_map.find(name); + if (pltrel_iter == plt_rel_map.end()) + continue; + + Symbol *stub_sym = iter->second[0]; + relocationEntry re(stub_sym->getOffset(), + pltrel_iter->second, + name, + targ_sym); + fbt_.push_back(re); + } + } + + // 1st plt entry is special. + next_plt_entry_addr += plt_entry_size_; + + } else if (getArch() == Dyninst::Arch_aarch64) + { + next_plt_entry_addr += 2 * plt_entry_size_; + } else { + next_plt_entry_addr += 4*(plt_entry_size_); //1st 4 entries are special + } + + + Elf_X_Sym sym = symdata.get_sym(); + Elf_X_Rel rel = reldata.get_rel(); + Elf_X_Rela rela = reldata.get_rela(); + const char *strs = strdata.get_string(); + + if (sym.isValid() && (rel.isValid() || rela.isValid()) && strs) { + + // Sometimes, PPC32 Linux may use this loop to update fbt entries. + // Should stay -1 for all other platforms. See notes above. + int fbt_iter = -1; + if (fbt_.size() > 0 && !fbt_[0].rel_addr() && fbt_[0].name() != "@plt") + fbt_iter = 0; + + for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { + long offset; + long addend; + long index; + unsigned long type; + Region::RegionType rtype; + + switch (reldata.d_type()) { + case ELF_T_REL: + offset = rel.r_offset(i); + addend = 0; + index = rel.R_SYM(i); + type = rel.R_TYPE(i); + rtype = Region::RT_REL; + break; + + case ELF_T_RELA: + offset = rela.r_offset(i); + addend = rela.r_addend(i); + index = rela.R_SYM(i); + type = rela.R_TYPE(i); + rtype = Region::RT_RELA; + break; + + default: + // We should never reach this case. + return false; + }; + + std::string targ_name = &strs[ sym.st_name(index) ]; + vector dynsym_list; + if (symbols_.find(targ_name) != symbols_.end()) + { + vector &syms = symbols_[&strs[ sym.st_name(index)]]; + for (vector::iterator i = syms.begin(); i != syms.end(); i++) { + if (!(*i)->isInDynSymtab()) + continue; + dynsym_list.push_back(*i); } + } + else { + dynsym_list.clear(); + } #if defined(os_vxworks) // VxWorks Kernel Images don't use PLT's, but we'll use the fbt to @@ -1541,11 +1540,14 @@ void Object::load_object(bool alloc_syms) } get_valid_memory_areas(*elfHdr); -#if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64)) - if (eh_frame_scnp != 0 && gcc_except != 0) +#if (defined(os_linux) || defined(os_freebsd)) + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { - find_catch_blocks(eh_frame_scnp, gcc_except, - txtaddr, dataddr, catch_addrs_); + if (eh_frame_scnp != 0 && gcc_except != 0) + { + find_catch_blocks(eh_frame_scnp, gcc_except, + txtaddr, dataddr, catch_addrs_); + } } #endif if (interp_scnp) { @@ -1727,10 +1729,12 @@ void Object::load_shared_object(bool alloc_syms) get_valid_memory_areas(*elfHdr); -#if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64)) - if (eh_frame_scnp != 0 && gcc_except != 0) { - find_catch_blocks(eh_frame_scnp, gcc_except, - txtaddr, dataddr, catch_addrs_); +#if (defined(os_linux) || defined(os_freebsd)) + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { + if (eh_frame_scnp != 0 && gcc_except != 0) { + find_catch_blocks(eh_frame_scnp, gcc_except, + txtaddr, dataddr, catch_addrs_); + } } #endif @@ -1949,7 +1953,6 @@ void Object::parse_opd(Elf_X_Shdr *opd_hdr) { // Let's read this puppy unsigned long *buf = (unsigned long *)data.d_buf(); - // In some cases, the OPD is a set of 3-tuples: . // In others, it's a set of 2-tuples. Since we can't tell the difference, we // instead look for function offsets. @@ -3030,7 +3033,7 @@ bool parseCompilerType(Object *objPtr) #endif -#if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64)) +#if (defined(os_linux) || defined(os_freebsd)) static unsigned long read_uleb128(const unsigned char *data, unsigned *bytes_read) { From 6e15735557c9a269ba0bbb6042024f27d4dcc574 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 3 Oct 2016 17:29:29 -0500 Subject: [PATCH 092/180] Clear srcfiles on each invocation of buildSrcFiles, so we're looking at the right module's file list. --- symtabAPI/src/dwarfWalker.C | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 2b09cf31ee..b55bd60c5a 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -259,11 +259,16 @@ void DwarfParseActions::setModuleFromName(std::string moduleName) bool DwarfWalker::buildSrcFiles(Dwarf_Die entry) { Dwarf_Signed cnt = 0; DWARF_ERROR_RET(dwarf_srcfiles(entry, &srcFileList_, &cnt, NULL)); + srcFiles_.clear(); srcFiles_.push_back(""); for (unsigned i = 0; i < cnt; ++i) { srcFiles_.push_back(srcFileList_[i]); freeList.push_back(boost::shared_ptr(const_cast(srcFiles_[i]), boost::bind(dwarf_dealloc, dbg(), _1, DW_DLA_STRING))); } + for(int i = 0; i < srcFiles_.size(); ++i) + { + printf("srcfiles[%d] = %s\n", i, srcFiles_[i]); + } freeList.push_back(boost::shared_ptr(srcFileList_, boost::bind(dwarf_dealloc, dbg(), _1, DW_DLA_LIST))); return true; } @@ -1600,7 +1605,7 @@ bool DwarfWalker::getLineInformation(Dwarf_Unsigned &variableLineNo, Dwarf_Unsigned fileNameDeclVal; DWARF_FAIL_RET(dwarf_formudata(fileDeclAttribute, &fileNameDeclVal, NULL)); dwarf_dealloc( dbg(), fileDeclAttribute, DW_DLA_ATTR ); - if (fileNameDeclVal >= srcFiles().size() || fileNameDeclVal < 0) { + if (fileNameDeclVal >= srcFiles().size()) { dwarf_printf("Dwarf error reading line index %d from srcFiles of size %lu\n", fileNameDeclVal, srcFiles().size()); return false; @@ -1723,7 +1728,7 @@ bool DwarfWalker::findString(Dwarf_Half attr, bool result = findConstant(attr, line_index, entry(), dbg()); if (!result) return false; - if (line_index > srcFiles().size()) { + if (line_index >= srcFiles().size()) { dwarf_printf("Dwarf error reading line index %d from srcFiles of size %lu\n", line_index, srcFiles().size()); return false; From 934f2bd2887d5dcfa68915283924d052eb26b558 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 4 Oct 2016 11:56:40 -0500 Subject: [PATCH 093/180] Remove debug output --- symtabAPI/src/dwarfWalker.C | 4 ---- 1 file changed, 4 deletions(-) diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index b55bd60c5a..67d28c8ab3 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -265,10 +265,6 @@ bool DwarfWalker::buildSrcFiles(Dwarf_Die entry) { srcFiles_.push_back(srcFileList_[i]); freeList.push_back(boost::shared_ptr(const_cast(srcFiles_[i]), boost::bind(dwarf_dealloc, dbg(), _1, DW_DLA_STRING))); } - for(int i = 0; i < srcFiles_.size(); ++i) - { - printf("srcfiles[%d] = %s\n", i, srcFiles_[i]); - } freeList.push_back(boost::shared_ptr(srcFileList_, boost::bind(dwarf_dealloc, dbg(), _1, DW_DLA_LIST))); return true; } From 5d1a8d984e22fb26149d78f1706401387283a976 Mon Sep 17 00:00:00 2001 From: John Detter Date: Tue, 4 Oct 2016 16:43:28 -0500 Subject: [PATCH 094/180] Improved the findMain analysis significantly --- dyninstAPI/src/image.C | 142 +++++++++++++++++++++++++++++------------ 1 file changed, 102 insertions(+), 40 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index f5cb7d8b41..d03c33dbe0 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -605,20 +605,20 @@ int image::findMain() if (!eReg) return -1; - Address eStart = eReg->getMemOffset(); + // Address eStart = eReg->getMemOffset(); if(!foundMain) { logLine( "No main symbol found: creating symbol for main\n" ); //find and add main to allsymbols - const unsigned char* p; + // const unsigned char* p; - p = (( const unsigned char * ) eReg->getPtrToRawData()); + // p = (( const unsigned char * ) eReg->getPtrToRawData()); - if (eAddr > eStart) { - p += (eAddr - eStart); - } + // if (eAddr > eStart) { + // p += (eAddr - eStart); + // } bool mode_64 = false; switch(linkedFile->getAddressWidth()) { @@ -663,6 +663,7 @@ int image::findMain() FILE__, __LINE__); return -1; } + CodeRegion* region = *regions.begin(); assert(region); @@ -672,6 +673,7 @@ int image::findMain() /* Get the parsed Function */ vector funcs; Function* func = co.findFuncByEntry(region, entry_point); + if(!func) { startup_printf("%s[%u]: No functions found in our region.\n", @@ -679,54 +681,108 @@ int image::findMain() return -1; } - /* Use dataflow analysis here to determine the value of EDI */ - const unsigned char* raw = p; - instruction insn; - insn.setInstruction(raw); - Address insn_addr = entry_point; + /* Get the call edges for this function */ + Function::edgelist list = func->callEdges(); + + /* There should be at least one edge */ + ParseAPI::Edge* e = *list.begin(); - const unsigned char *last_insn = NULL; - while(!insn.isCall()) + if(!e) { - last_insn = raw; - raw += insn.size(); - insn.setInstruction(raw); + startup_printf("%s[%u]: Error: no call edges found for this function.\n", + FILE__, __LINE__); + return -1; } - if(!last_insn) /* We cannot do analysis on this */ + /* get the block for this call edge (source) */ + Block* b = e->src(); + assert(b); + + /* Get the address of the last instruction in the block (the call) */ + Address insn_addr = b->lastInsnAddr(); + void* insn_raw = region->getPtrToInstruction(insn_addr); + + /* Make sure insn_raw is valid */ + if(!insn_raw) { - startup_printf("%s[%u]: Our main analysis doesn't apply to " - "this compiler.\n", + startup_printf("%s[%u]: Error: no instruction pointer in region.\n", FILE__, __LINE__); return -1; } - /* Calculate the address of the instruction */ - insn_addr += last_insn - p; + /* Needed to get the size of the call instruction */ + instruction insn; + insn.setInstruction((const unsigned char*)insn_raw); - /* Decode the instruction */ + /* We also need the instructionAPI representation of the call instruction */ InstructionAPI::InstructionDecoder* decoder = NULL; if(mode_64) { decoder = new InstructionAPI::InstructionDecoder( - last_insn, insn.size(), Dyninst::Arch_x86_64); + insn_raw, insn.size(), Dyninst::Arch_x86_64); } else { decoder = new InstructionAPI::InstructionDecoder( - last_insn, insn.size(), Dyninst::Arch_x86); + insn_raw, insn.size(), Dyninst::Arch_x86); } - InstructionAPI::Instruction::Ptr insn_ptr = decoder->decode(last_insn); + + /* Decode just the call instruction */ + InstructionAPI::Instruction::Ptr insn_ptr = decoder->decode( + (const unsigned char*)insn_raw); + + /* Use dataflow analysis here to determine the value of EDI */ + // const unsigned char* raw = p; + // instruction insn; + // // insn.setInstruction(raw); + // Address insn_addr = entry_point; + + // const unsigned char *last_insn = NULL; + // while(!insn.isCall()) + // { + // last_insn = raw; + // raw += insn.size(); + // insn.setInstruction(raw); + // } + + // if(!last_insn) /* We cannot do analysis on this */ + // { + // startup_printf("%s[%u]: Our main analysis doesn't apply to " + // "this compiler.\n", + // FILE__, __LINE__); + // return -1; + // } + + /* Calculate the address of the instruction */ + // insn_addr += last_insn - p; + + /* Decode the instruction */ + // InstructionAPI::InstructionDecoder* decoder = NULL; + // if(mode_64) + // { + // decoder = new InstructionAPI::InstructionDecoder( + // last_insn, insn.size(), Dyninst::Arch_x86_64); + // } else { + // decoder = new InstructionAPI::InstructionDecoder( + // last_insn, insn.size(), Dyninst::Arch_x86); + // } + // InstructionAPI::Instruction::Ptr insn_ptr = decoder->decode(last_insn); /* Get the block for this instruction */ - assert(region->contains(insn_addr)); - std::set blocks; - co.findBlocks(region, insn_addr, blocks); - if(blocks.size() == 1) - { - startup_printf("%s[%u]: WARNING: overlapping blocks.\n", - FILE__, __LINE__); - } - Block* b = *blocks.begin(); - assert(b); + // assert(region->contains(insn_addr)); + // std::set blocks; + // co.findBlocks(region, insn_addr, blocks); + // if(blocks.size() != 1) + // { + // startup_printf("%s[%u]: WARNING: overlapping blocks.\n", + // FILE__, __LINE__); + // } + + // Block* b = *blocks.begin(); + + // if(!b) + // { + // startup_printf("%s[%u]: Error: no block for this code region?"); + // return -1; + // } /* Let's get the assignment for this instruction. */ std::vector assignments; @@ -738,13 +794,19 @@ int image::findMain() std::pair res = DataflowAPI::SymEval::expand(assignment, false); AST::Ptr ast = res.first; - FindMainVisitor fmv; - ast->accept(&fmv); - if(fmv.resolved) + if(!ast) { - mainAddress = fmv.target; - } else { + /* expand failed */ mainAddress = 0x0; + } else { + FindMainVisitor fmv; + ast->accept(&fmv); + if(fmv.resolved) + { + mainAddress = fmv.target; + } else { + mainAddress = 0x0; + } } } #else From 762f6a64f6996cfe19dd474f4f426a6cd8469f19 Mon Sep 17 00:00:00 2001 From: John Detter Date: Wed, 5 Oct 2016 12:52:18 -0500 Subject: [PATCH 095/180] Deleted the old code block --- dyninstAPI/src/image.C | 55 ------------------------------------------ 1 file changed, 55 deletions(-) diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index d03c33dbe0..05bf0ccd63 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -729,61 +729,6 @@ int image::findMain() InstructionAPI::Instruction::Ptr insn_ptr = decoder->decode( (const unsigned char*)insn_raw); - /* Use dataflow analysis here to determine the value of EDI */ - // const unsigned char* raw = p; - // instruction insn; - // // insn.setInstruction(raw); - // Address insn_addr = entry_point; - - // const unsigned char *last_insn = NULL; - // while(!insn.isCall()) - // { - // last_insn = raw; - // raw += insn.size(); - // insn.setInstruction(raw); - // } - - // if(!last_insn) /* We cannot do analysis on this */ - // { - // startup_printf("%s[%u]: Our main analysis doesn't apply to " - // "this compiler.\n", - // FILE__, __LINE__); - // return -1; - // } - - /* Calculate the address of the instruction */ - // insn_addr += last_insn - p; - - /* Decode the instruction */ - // InstructionAPI::InstructionDecoder* decoder = NULL; - // if(mode_64) - // { - // decoder = new InstructionAPI::InstructionDecoder( - // last_insn, insn.size(), Dyninst::Arch_x86_64); - // } else { - // decoder = new InstructionAPI::InstructionDecoder( - // last_insn, insn.size(), Dyninst::Arch_x86); - // } - // InstructionAPI::Instruction::Ptr insn_ptr = decoder->decode(last_insn); - - /* Get the block for this instruction */ - // assert(region->contains(insn_addr)); - // std::set blocks; - // co.findBlocks(region, insn_addr, blocks); - // if(blocks.size() != 1) - // { - // startup_printf("%s[%u]: WARNING: overlapping blocks.\n", - // FILE__, __LINE__); - // } - - // Block* b = *blocks.begin(); - - // if(!b) - // { - // startup_printf("%s[%u]: Error: no block for this code region?"); - // return -1; - // } - /* Let's get the assignment for this instruction. */ std::vector assignments; Dyninst::AssignmentConverter assign_convert(true, false); From fc6692f6e2955920fcfe7238fd2ac1212e404780 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 11 Oct 2016 17:56:04 -0700 Subject: [PATCH 096/180] proccontrol: check thread handle before calculating TLS --- proccontrol/src/int_thread_db.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proccontrol/src/int_thread_db.C b/proccontrol/src/int_thread_db.C index f4d5fc9c1d..80476fb29c 100644 --- a/proccontrol/src/int_thread_db.C +++ b/proccontrol/src/int_thread_db.C @@ -1635,7 +1635,7 @@ async_ret_t thread_db_process::plat_calcTLSAddress(int_thread *thread, int_libra Address &outaddr, set &resps) { thread_db_thread *thrd = dynamic_cast(thread); - if (!thrd) { + if (!thrd || !thrd->initThreadHandle()) { perr_printf("Thread_db not supported on thread %d/%d\n", getPid(), thread->getLWP()); setLastError(err_unsupported, "TLS Operations not supported on this thread\n"); return aret_error; From cd6de9fae373ed0b36d4bfe1de1c78bb2ed1cf91 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 12 Oct 2016 16:19:32 -0500 Subject: [PATCH 097/180] Update Elf_X.C --- elf/src/Elf_X.C | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index 84609a2005..cd175c60f5 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -45,6 +45,7 @@ #include #include #include +#include using namespace std; using boost::crc_32_type; @@ -854,6 +855,24 @@ size_t Elf_X_Data::d_align() const { return data->d_align; } +void Elf_X_Data::xlatetom(unsigned int encode) +{ + if(is64) + { + elf64_xlatetom(data, data, encode); + } else { + elf32_xlatetom(data, data, encode); + } +} +void Elf_X_Data::xlatetof(unsigned int encode) +{ + if(is64) + { + elf64_xlatetof(data, data, encode); + } else { + elf32_xlatetof(data, data, encode); + } +} // Write Interface void Elf_X_Data::d_buf(void *input) From a3b08c732d6dc2712ef231b44e455b9cf09d8f5c Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 12 Oct 2016 16:20:33 -0500 Subject: [PATCH 098/180] Add xlatetof and xlatetom. --- elf/h/Elf_X.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/elf/h/Elf_X.h b/elf/h/Elf_X.h index ce8a9dd38e..f4e74a0baa 100644 --- a/elf/h/Elf_X.h +++ b/elf/h/Elf_X.h @@ -259,6 +259,8 @@ class DYNELF_EXPORT Elf_X_Data { size_t d_size() const; off_t d_off() const; size_t d_align() const; + void xlatetom(unsigned int encode); + void xlatetof(unsigned int encode); // Write Interface void d_buf(void *input); From 85c4fc25634304867933c0d38f30adcc58d248f5 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 18 Oct 2016 17:10:52 -0500 Subject: [PATCH 099/180] pefoley2-boost_win (#194) Make boost-as-external cross-platform. --- CMakeLists.txt | 3 +++ appveyor.yml | 6 +----- cmake/packages.cmake | 37 ++++++++++++++++++++++++++++++++++--- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3e02847d6..77a6626df6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,3 +220,6 @@ if(UNIX) endif() endif() +if(NOT BOOST_FOUND) + add_dependencies(common boost) +endif() diff --git a/appveyor.yml b/appveyor.yml index 9b19cc77c1..841e3ff925 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ build: parallel: true project: Dyninst.sln - verbosity: normal + verbosity: detailed clone_depth: 5 @@ -11,9 +11,5 @@ platform: configuration: - Release -environment: - BOOST_ROOT: C:\Libraries\boost_1_60_0 - BOOST_LIBRARYDIR: C:\Libraries\boost_1_60_0\lib32-msvc-14.0 - before_build: - cmake . diff --git a/cmake/packages.cmake b/cmake/packages.cmake index 4f9160a703..c20662ee63 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -98,9 +98,10 @@ endif() # an older CMake and it complains that it can't find Boost set(Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0" "1.48" "1.48.0" "1.49" "1.49.0" "1.50" "1.50.0" "1.51" "1.51.0" "1.52" "1.52.0" - "1.53" "1.53.0" "1.54" "1.54.0" "1.55" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" "1.58" "1.58.0" "1.59" "1.59.0") + "1.53" "1.53.0" "1.54" "1.54.0" "1.55" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" "1.58" "1.58.0" "1.59" "1.59.0" + "1.60" "1.60.0" "1.61" "1.61.0" "1.62" "1.62.0") -# set (Boost_DEBUG ON) +set (Boost_DEBUG ON) set (PATH_BOOST "/usr" CACHE STRING "Path to boost") set(Boost_USE_MULTITHREADED ON) @@ -126,7 +127,37 @@ if(DEFINED PATH_BOOST OR set(Boost_NO_SYSTEM_PATHS ON) endif() -find_package (Boost ${BOOST_MIN_VERSION} REQUIRED COMPONENTS thread system) + +find_package (Boost ${BOOST_MIN_VERSION} COMPONENTS thread system date_time) + + +if(NOT Boost_FOUND) + if(WIN32) + set(BOOST_BOOTSTRAP call bootstrap.bat) + set(BOOST_BUILD b2.exe) + set(BOOST_BASE boost/src/Boost) + else() + set(BOOST_BOOTSTRAP "./bootstrap.sh") + set(BOOST_BUILD "./b2") + set(BOOST_BASE boost/src/boost) + endif() + + message(STATUS "No boost found, attempting to build as external project") + cmake_minimum_required (VERSION 2.8.11) + include(ExternalProject) + ExternalProject_Add(boost + PREFIX ${CMAKE_BINARY_DIR}/boost + URL http://downloads.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.7z + URL_MD5 bb1dad35ad069e8d7c8516209a51053c + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND ${BOOST_BOOTSTRAP} --prefix=${CMAKE_INSTALL_PREFIX} + BUILD_COMMAND ${BOOST_BUILD} --with-system --with-thread --with-date_time --layout=versioned --ignore-site-config stage + INSTALL_COMMAND ${BOOST_BUILD} --with-system --with-thread --with-date_time --layout=versioned --ignore-site-config install + ) + set(Boost_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}) + set(Boost_LIBRARY_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}/stage/lib) + set(Boost_LIBRARIES -lboost_system -lboost_thread) +endif() link_directories ( ${Boost_LIBRARY_DIRS} ) From a8252fd9ace7dd837f98b0db750c588560feea95 Mon Sep 17 00:00:00 2001 From: Benjamin Welton Date: Wed, 19 Oct 2016 17:03:14 -0500 Subject: [PATCH 100/180] Added symbol linkage support for GNU unique linkage types (#209) * Added symbol linkage support for GNU unique linkage types * Added define guards around STB_GNU_UNIQUE --- symtabAPI/h/Symbol.h | 3 ++- symtabAPI/src/Object-elf.C | 3 +++ symtabAPI/src/emitElf.C | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/symtabAPI/h/Symbol.h b/symtabAPI/h/Symbol.h index 39a33bab30..2ebbea1da0 100644 --- a/symtabAPI/h/Symbol.h +++ b/symtabAPI/h/Symbol.h @@ -130,7 +130,8 @@ class SYMTAB_EXPORT Symbol : public Serializable, SL_UNKNOWN, SL_GLOBAL, SL_LOCAL, - SL_WEAK + SL_WEAK, + SL_UNIQUE }; static const char *symbolLinkage2Str(SymbolLinkage t); diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 804ee2d234..b6772d5f6e 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -1861,6 +1861,9 @@ static Symbol::SymbolLinkage pdelf_linkage(int elf_binding) case STB_LOCAL: return Symbol::SL_LOCAL; case STB_WEAK: return Symbol::SL_WEAK; case STB_GLOBAL: return Symbol::SL_GLOBAL; +#if defined(STB_GNU_UNIQUE) + case STB_GNU_UNIQUE: return Symbol::SL_UNIQUE; +#endif } return Symbol::SL_UNKNOWN; } diff --git a/symtabAPI/src/emitElf.C b/symtabAPI/src/emitElf.C index f7edb211fb..81e64d86ef 100644 --- a/symtabAPI/src/emitElf.C +++ b/symtabAPI/src/emitElf.C @@ -225,6 +225,9 @@ static int elfSymBind(Symbol::SymbolLinkage sLinkage) case Symbol::SL_LOCAL: return STB_LOCAL; case Symbol::SL_WEAK: return STB_WEAK; case Symbol::SL_GLOBAL: return STB_GLOBAL; +#if defined(STB_GNU_UNIQUE) + case Symbol::SL_UNIQUE: return STB_GNU_UNIQUE; +#endif default: return STB_LOPROC; } } From 8a6783504cb65771cb06f2ab0e9252765607005d Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Tue, 25 Oct 2016 16:13:05 -0700 Subject: [PATCH 101/180] Fix errors when thread disappears during attach --- proccontrol/src/linux.C | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C index 407a77ec6e..5c4124dda9 100644 --- a/proccontrol/src/linux.C +++ b/proccontrol/src/linux.C @@ -1009,17 +1009,28 @@ bool linux_process::plat_getOSRunningStates(std::map &runnin snprintf(proc_stat_name, 128, "/proc/%d/stat", *i); FILE *sfile = fopen(proc_stat_name, "r"); - if (sfile == NULL) { + if (*i == getPid() && sfile == NULL) { pthrd_printf("Failed to open /proc/%d/stat file\n", *i); setLastError(err_noproc, "Failed to find /proc files for debuggee"); return false; } - if( fread(sstat, 1, 256, sfile) == 0 ) { + else if (sfile == NULL) { + //thread died between the above getThreadLWPs and the /proc/pid/stat open + // just drop it from the to-attach list. + continue; + } + size_t result = fread(sstat, 1, 256, sfile); + if (*i == getPid() && result == 0) { pthrd_printf("Failed to read /proc/%d/stat file \n", *i); setLastError(err_noproc, "Failed to find /proc files for debuggee"); fclose(sfile); return false; } + else if (result == 0) { + fclose(sfile); + continue; + } + fclose(sfile); sstat[255] = '\0'; From 159adf90b6733d5ec2700f0729af919433270930 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 28 Oct 2016 18:09:16 -0700 Subject: [PATCH 102/180] proccontrol: refactor plat_getOSRunningStates - The file is now opened with ifstream for RAII. - The former paren_level logic is removed to instead scan for ") R ". (If there were parens in the command, they might not be balanced!) --- proccontrol/src/linux.C | 62 +++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C index 5c4124dda9..d701693761 100644 --- a/proccontrol/src/linux.C +++ b/proccontrol/src/linux.C @@ -40,6 +40,7 @@ #include #include #include +#include #include "common/h/dyn_regs.h" #include "common/h/dyntypes.h" @@ -1001,51 +1002,38 @@ bool linux_process::plat_getOSRunningStates(std::map &runnin for(vector::iterator i = lwps.begin(); i != lwps.end(); ++i) { + const auto ignore_max = std::numeric_limits::max(); char proc_stat_name[128]; - char sstat[256]; - char *status; - int paren_level = 1; snprintf(proc_stat_name, 128, "/proc/%d/stat", *i); - FILE *sfile = fopen(proc_stat_name, "r"); + ifstream sfile(proc_stat_name); - if (*i == getPid() && sfile == NULL) { - pthrd_printf("Failed to open /proc/%d/stat file\n", *i); - setLastError(err_noproc, "Failed to find /proc files for debuggee"); - return false; - } - else if (sfile == NULL) { - //thread died between the above getThreadLWPs and the /proc/pid/stat open - // just drop it from the to-attach list. - continue; - } - size_t result = fread(sstat, 1, 256, sfile); - if (*i == getPid() && result == 0) { - pthrd_printf("Failed to read /proc/%d/stat file \n", *i); - setLastError(err_noproc, "Failed to find /proc files for debuggee"); - fclose(sfile); - return false; - } - else if (result == 0) { - fclose(sfile); - continue; - } - - fclose(sfile); + while (sfile.good()) { - sstat[255] = '\0'; - status = sstat; + // The stat looks something like: 123 (command) R 456... + // We'll just look for the ") R " part. + if (sfile.ignore(ignore_max, ')').peek() == ' ') { + char space, state; - while (*status != '\0' && *(status++) != '(') ; - while (*status != '\0' && paren_level != 0) { - if (*status == '(') paren_level++; - if (*status == ')') paren_level--; - status++; - } + // Eat the space we peeked and grab the state char. + if (sfile.get(space).get(state).peek() == ' ') { + // Found the state char -- 'T' means it's already stopped. + runningStates.insert(make_pair(*i, (state != 'T'))); + break; + } - while (*status == ' ') status++; + // Restore the state char and try again + sfile.unget(); + } + } - runningStates.insert(make_pair(*i, (*status != 'T'))); + if (!sfile.good() && (*i == getPid())) { + // Only the main thread is treated as an error. Other threads may + // have exited between getThreadLWPs and /proc/pid/stat open or read. + pthrd_printf("Failed to read /proc/%d/stat file\n", *i); + setLastError(err_noproc, "Failed to find /proc files for debuggee"); + return false; + } } return true; From 8ad13d3f102c71007ef49c9b11ef96bbca8dfc0e Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 30 Oct 2016 17:28:12 -0400 Subject: [PATCH 103/180] Fix typo in Boost_FOUND conditional --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 77a6626df6..710a5b3f4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,6 +220,6 @@ if(UNIX) endif() endif() -if(NOT BOOST_FOUND) +if(NOT Boost_FOUND) add_dependencies(common boost) endif() From 998b02833a46e26667b75344b6ba6777b56e3b28 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 30 Oct 2016 17:34:44 -0400 Subject: [PATCH 104/180] Disable unnecessary FindBoost debugging output by default --- cmake/packages.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index c20662ee63..c500533830 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -101,7 +101,7 @@ set(Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0" "1.48" "1.48.0" "1.49" "1.49.0" "1.53" "1.53.0" "1.54" "1.54.0" "1.55" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" "1.58" "1.58.0" "1.59" "1.59.0" "1.60" "1.60.0" "1.61" "1.61.0" "1.62" "1.62.0") -set (Boost_DEBUG ON) +# set (Boost_DEBUG ON) set (PATH_BOOST "/usr" CACHE STRING "Path to boost") set(Boost_USE_MULTITHREADED ON) From 859cb778e20b619443c943c96dd1851da763142b Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 30 Oct 2016 18:34:58 -0400 Subject: [PATCH 105/180] Properly handle SL_UNIQUE in switch statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit e.g. /home/peter/dyninst/symtabAPI/src/Object.C:97:20: warning: enumeration value ‘SL_UNIQUE’ not handled in switch [-Wswitch] /home/peter/dyninst/symtabAPI/src/Symtab.C:3465:11: warning: enumeration value ‘SL_UNIQUE’ not handled in switch [-Wswitch] --- symtabAPI/src/Object.C | 1 + symtabAPI/src/Symtab.C | 1 + 2 files changed, 2 insertions(+) diff --git a/symtabAPI/src/Object.C b/symtabAPI/src/Object.C index 2ca0f94354..b8a6faf7db 100644 --- a/symtabAPI/src/Object.C +++ b/symtabAPI/src/Object.C @@ -99,6 +99,7 @@ void print_symbols( std::vector< Symbol *>& allsymbols ) { case Symbol::SL_GLOBAL: fprintf(fd, " GL"); break; case Symbol::SL_LOCAL: fprintf(fd, " LO"); break; case Symbol::SL_WEAK: fprintf(fd, " WK"); break; + case Symbol::SL_UNIQUE: fprintf(fd, " UQ"); break; } switch (sym->getVisibility()) { case Symbol::SV_UNKNOWN: fprintf(fd, " ???"); break; diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index 32d2abda09..42f600aa62 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -3468,6 +3468,7 @@ const char *Symbol::symbolLinkage2Str(SymbolLinkage t) CASE_RETURN_STR(SL_GLOBAL); CASE_RETURN_STR(SL_LOCAL); CASE_RETURN_STR(SL_WEAK); + CASE_RETURN_STR(SL_UNIQUE); }; return "invalid symbol linkage"; From d8c56be7a07e785d0cabecc900594a983690ebb0 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sat, 14 May 2016 15:28:25 -0400 Subject: [PATCH 106/180] lto --- cmake/optimization.cmake | 43 ++++++++++++++++++++++++++++++++-------- cmake/shared.cmake | 2 ++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/cmake/optimization.cmake b/cmake/optimization.cmake index 64a4b2d375..951d7cb9bf 100644 --- a/cmake/optimization.cmake +++ b/cmake/optimization.cmake @@ -2,22 +2,49 @@ if (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_C_COMPILER_ID} MATCHES Clang OR ${CMAKE_C_COMPILER_ID} MATCHES GNU OR ${CMAKE_C_COMPILER_ID} MATCHES Intel) +if(ENABLE_LTO) + set(LTO_FLAGS "-flto") + set(LTO_LINK_FLAGS "-fuse-ld=gold") +else() + set(LTO_FLAGS "") + set(LTO_LINK_FLAGS "") +endif() set (CMAKE_C_FLAGS_DEBUG "-O0 -g") -set (CMAKE_C_FLAGS_RELEASE "-O2") set (CMAKE_CXX_FLAGS_DEBUG "-O0 -g") -set (CMAKE_CXX_FLAGS_RELEASE "-O2") -set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") -set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + +set (CMAKE_C_FLAGS_RELEASE "-O2 ${LTO_FLAGS}") +set (CMAKE_CXX_FLAGS_RELEASE "-O2 ${LTO_FLAGS}") + +set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g ${LTO_FLAGS}") +set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g ${LTO_FLAGS}") + set (FORCE_FRAME_POINTER "-fno-omit-frame-pointer") # Ensure each library is fully linked set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") + +set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LTO_LINK_FLAGS}") +set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_LINK_FLAGS}") else (MSVC) +if(ENABLE_LTO) + set(LTO_FLAGS "/GL") + set(LTO_LINK_FLAGS "/LTCG") +else() + set(LTO_FLAGS "") + set(LTO_LINK_FLAGS "") +endif() set (CMAKE_C_FLAGS_DEBUG "/MP /Od /Zi /MDd /D_DEBUG") -set (CMAKE_C_FLAGS_RELEASE "/MP /O2 /MD /D NDEBUG") set (CMAKE_CXX_FLAGS_DEBUG "/MP /Od /Zi /MDd /D_DEBUG") -set (CMAKE_CXX_FLAGS_RELEASE "/MP /O2 /MD /D NDEBUG") -set (CMAKE_C_FLAGS_RELWITHDEBINFO "/MP /O2 /Zi /MD /D NDEBUG") -set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MP /O2 /Zi /MD /D NDEBUG") + +set (CMAKE_C_FLAGS_RELEASE "/MP /O2 /MD /D NDEBUG ${LTO_FLAGS}") +set (CMAKE_CXX_FLAGS_RELEASE "/MP /O2 /MD /D NDEBUG ${LTO_FLAGS}") + +set (CMAKE_C_FLAGS_RELWITHDEBINFO "/MP /O2 /Zi /MD /D NDEBUG ${LTO_FLAGS}") +set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MP /O2 /Zi /MD /D NDEBUG ${LTO_FLAGS}") + set (FORCE_FRAME_POINTER "/Oy-") + +set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LTO_LINK_FLAGS}") +set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_LINK_FLAGS}") +set (CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${LTO_LINK_FLAGS}") endif() message(STATUS "Set optimization flags") diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 1dc6e56d67..a97b335e3e 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -84,6 +84,8 @@ endfunction() #Change to switch between libiberty/libstdc++ demangler #set(USE_GNU_DEMANGLER 1) +set (ENABLE_LTO FALSE CACHE BOOL "Enable Link-Time Optimization") + set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${DYNINST_ROOT}/cmake/Modules") include (${DYNINST_ROOT}/cmake/platform.cmake) if (NOT ${PROJECT_NAME} MATCHES DyninstRT) From c08ef1c7f389c18bbca55e8249ee63808de7ec36 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sat, 14 May 2016 21:08:30 -0400 Subject: [PATCH 107/180] fixes --- dyninstAPI/src/BPatch_addressSpace.C | 6 ++++-- symtabAPI/src/dwarfWalker.C | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dyninstAPI/src/BPatch_addressSpace.C b/dyninstAPI/src/BPatch_addressSpace.C index 37a0e59c2b..0e930e9c79 100644 --- a/dyninstAPI/src/BPatch_addressSpace.C +++ b/dyninstAPI/src/BPatch_addressSpace.C @@ -96,8 +96,10 @@ BPatch_function *BPatch_addressSpace::findOrCreateBPFunc(Dyninst::PatchAPI::Patc // check to see if the func_instance refers to a different // module, and that module contains a bpatch_func - assert(fi->mod() != NULL); - BPatch_module* containing = getImage()->findModule(fi->mod()->fileName().c_str()); + BPatch_module* containing = nullptr; + if (fi->mod() != NULL) { + containing = getImage()->findModule(fi->mod()->fileName().c_str()); + } // findModule has a tendency to make new function objects... so // check the map again diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 67d28c8ab3..dfb7b42f1f 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -1124,7 +1124,7 @@ bool DwarfWalker::parseInheritance() { dwarf_printf("(0x%lx) Found %p as superclass\n", id(), superClass); - visibility_t visibility; + visibility_t visibility = visUnknown; if (!findVisibility(visibility)) return false; /* Add a readily-recognizable 'bad' field to represent the superclass. @@ -1182,7 +1182,7 @@ bool DwarfWalker::parseEnumEntry() { if (!findName(curName())) return false; - long value; + long value = 0; bool valid; if (!findValue(value, valid)) return false; From 5ca02b3ac109b945357a718f3f0b08a00a2dd371 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 2 Jun 2016 11:47:30 -0500 Subject: [PATCH 108/180] Rename emitElf64, fix 32-bit build --- cmake/shared.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 1dc6e56d67..d3df0cd60a 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -3,7 +3,7 @@ set (DYNINST_MINOR_VERSION 2) set (DYNINST_PATCH_VERSION 0) # Debugging -# set(Boost_DEBUG 1) +set(Boost_DEBUG 1) set (SOVERSION "${DYNINST_MAJOR_VERSION}.${DYNINST_MINOR_VERSION}") set (LIBVERSION "${SOVERSION}.${DYNINST_PATCH_VERSION}") From f1eeee1382c573f96a3d1105802bca731e166c58 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 12 Jul 2016 13:58:47 -0500 Subject: [PATCH 109/180] Make Statement's filenames const char* pointing into the string table, not just LineInformation's copies of same. --- symtabAPI/h/Module.h | 12 +++++++----- symtabAPI/src/LineInformation.C | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 2db2ac8144..bce04eeebe 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -53,22 +53,24 @@ class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable Statement(const char *file, unsigned int line, unsigned int col = 0, Offset start_addr = (Offset) -1L, Offset end_addr = (Offset) -1L) : - file_(file ? std::string(file) : std::string()), + file_(file), line_(line), start_addr_(start_addr), end_addr_(end_addr), - first(file_.c_str()), + first(file_), second(line_), column(col) { } - std::string file_; // Maybe this should be module? + const char* file_; // Maybe this should be module? unsigned int line_; Offset start_addr_; Offset end_addr_; public: + // DEPRECATED. First and second need to die, and column should become an accessor. + // Duplication of data is both bad and stupid, okay? const char *first; unsigned int second; unsigned int column; @@ -85,7 +87,7 @@ class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable Offset startAddr() { return start_addr_;} Offset endAddr() {return end_addr_;} - const std::string &getFile() { return file_;} + std::string getFile() { return file_;} unsigned int getLine() {return line_;} unsigned int getColumn() {return column;} @@ -94,7 +96,7 @@ class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable // Does dyninst really need these? void setLine(unsigned int l) {line_ = l;} void setColumn(unsigned int l) {column = l;} - void setFile(const char * l) {file_ = std::string(l); first = file_.c_str();} + void setFile(const char * l) {file_ = l; first = file_;} void setStartAddr(Offset l) {start_addr_ = l;} void setEndAddr(Offset l) {end_addr_ = l;} }; diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 068d4a5bec..1e2baacfef 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -73,7 +73,7 @@ void LineInformation::addLineInfo(LineInformation *lineInfo) for (; iter != lineInfo->end(); iter++) { - addLine(iter->second.file_.c_str(), iter->second.line_, iter->second.column, + addLine(iter->second.file_, iter->second.line_, iter->second.column, iter->first.first, iter->first.second); } } @@ -135,7 +135,7 @@ bool Statement::StatementLess::operator () ( const Statement &lhs, const Stateme { // dont bother with ordering by column information yet. - int strcmp_res = strcmp( lhs.file_.c_str(), rhs.file_.c_str()); + int strcmp_res = strcmp( lhs.file_, rhs.file_); if (strcmp_res < 0 ) return true; From 8bb77b23cc573ada4116e37aaa867666f7f28256 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 12 Jul 2016 15:09:50 -0500 Subject: [PATCH 110/180] Replace iterative dealloc with dwarf_srclines_dealloc, which should avoid certain leaks that were inherent in the iterative style. --- symtabAPI/src/Object-elf.C | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index b6772d5f6e..9317a6a93f 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4439,10 +4439,7 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) } /* end iteration over source line entries. */ /* Free this CU's source lines. */ - for ( int i = 0; i < lineCount; i++ ) { - dwarf_dealloc( dbg, lineBuffer[i], DW_DLA_LINE ); - } - dwarf_dealloc( dbg, lineBuffer, DW_DLA_LIST ); + dwarf_srclines_dealloc(dbg, lineBuffer, lineCount); } From 74febd671762791871f55f1413cc172fc03d0772 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 12 Jul 2016 16:00:12 -0500 Subject: [PATCH 111/180] Replace individual linesrc calls with srcfiles, allowing libdwarf to allocate once and us to do lookups by index rather than strcmp. --- symtabAPI/src/Object-elf.C | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 9317a6a93f..7da33b3eb3 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4324,6 +4324,10 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) } assert( status == DW_DLV_OK ); + char** srcfiles; + Dwarf_Signed fileCount; + + status = dwarf_srcfiles(cuDIE, &srcfiles, &fileCount, NULL); /* The 'lines' returned are actually interval markers; the code generated from lineNo runs from lineAddr up to but not including the lineAddr of the next line. */ @@ -4331,7 +4335,7 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) Dwarf_Unsigned previousLineNo = 0; Dwarf_Signed previousLineColumn = 0; Dwarf_Addr previousLineAddr = 0x0; - char * previousLineSource = NULL; + Dwarf_Unsigned previousLineSource = NULL; Offset baseAddr = getBaseAddress(); @@ -4371,8 +4375,10 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) char * lineSource; - status = dwarf_linesrc( lineBuffer[i], & lineSource, NULL ); + Dwarf_Unsigned srcfileindex; + status = dwarf_line_srcfileno(lineBuffer[i], &srcfileindex, NULL); if ( status != DW_DLV_OK ) { continue; } + lineSource = srcfiles[srcfileindex]; Dwarf_Bool isEndOfSequence; status = dwarf_lineendsequence( lineBuffer[i], & isEndOfSequence, NULL ); @@ -4383,7 +4389,7 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) /* If we're talking about the same (source file, line number) tuple, and it isn't the end of the sequence, we can coalesce the range. (The end of sequence marker marks discontinuities in the ranges.) */ - if ( lineNo == previousLineNo && strcmp( lineSource, previousLineSource ) == 0 + if ( lineNo == previousLineNo && ( srcfileindex == previousLineSource ) && ! isEndOfSequence ) { /* Don't update the prev* values; just keep going until we hit the end of @@ -4391,18 +4397,12 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) continue; } /* end if we can coalesce this range */ - char *canonicalLineSource; + char *canonicalLineSource = srcfiles[previousLineSource]; if (truncateLineFilenames) { - canonicalLineSource = strrchr( previousLineSource, '/' ); - if( canonicalLineSource == NULL ) { canonicalLineSource = previousLineSource; } + canonicalLineSource = strrchr( srcfiles[previousLineSource], '/' ); + if( canonicalLineSource == NULL ) { canonicalLineSource = srcfiles[previousLineSource]; } else { ++canonicalLineSource; } } - else { - canonicalLineSource = previousLineSource; - } - - - Dyninst::Offset startAddrToUse = previousLineAddr; Dyninst::Offset endAddrToUse = lineAddr; @@ -4428,9 +4428,8 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) isPreviousValid = false; } else { - if( isPreviousValid ) { dwarf_dealloc( dbg, previousLineSource, DW_DLA_STRING ); } previousLineNo = lineNo; - previousLineSource = lineSource; + previousLineSource = srcfileindex; previousLineAddr = lineAddr; previousLineColumn = lineOff; @@ -4440,6 +4439,11 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) /* Free this CU's source lines. */ dwarf_srclines_dealloc(dbg, lineBuffer, lineCount); + for(int i = 0; i < fileCount; ++i) + { + dwarf_dealloc(dbg, srcfiles[i], DW_DLA_STRING); + } + dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST); } From c52f9e410d040170e9e711ccacad7e61b6975a03 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 13 Jul 2016 13:44:45 -0500 Subject: [PATCH 112/180] Warning cleanup. --- .idea/deployment.xml | 14 ++++++++++++++ .idea/webServers.xml | 10 ++++++++++ symtabAPI/src/Object-elf.C | 32 ++++++++++++++------------------ 3 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 .idea/deployment.xml create mode 100644 .idea/webServers.xml diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000000..fb268c190c --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/webServers.xml b/.idea/webServers.xml new file mode 100644 index 0000000000..5820061605 --- /dev/null +++ b/.idea/webServers.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 7da33b3eb3..9317a6a93f 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4324,10 +4324,6 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) } assert( status == DW_DLV_OK ); - char** srcfiles; - Dwarf_Signed fileCount; - - status = dwarf_srcfiles(cuDIE, &srcfiles, &fileCount, NULL); /* The 'lines' returned are actually interval markers; the code generated from lineNo runs from lineAddr up to but not including the lineAddr of the next line. */ @@ -4335,7 +4331,7 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) Dwarf_Unsigned previousLineNo = 0; Dwarf_Signed previousLineColumn = 0; Dwarf_Addr previousLineAddr = 0x0; - Dwarf_Unsigned previousLineSource = NULL; + char * previousLineSource = NULL; Offset baseAddr = getBaseAddress(); @@ -4375,10 +4371,8 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) char * lineSource; - Dwarf_Unsigned srcfileindex; - status = dwarf_line_srcfileno(lineBuffer[i], &srcfileindex, NULL); + status = dwarf_linesrc( lineBuffer[i], & lineSource, NULL ); if ( status != DW_DLV_OK ) { continue; } - lineSource = srcfiles[srcfileindex]; Dwarf_Bool isEndOfSequence; status = dwarf_lineendsequence( lineBuffer[i], & isEndOfSequence, NULL ); @@ -4389,7 +4383,7 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) /* If we're talking about the same (source file, line number) tuple, and it isn't the end of the sequence, we can coalesce the range. (The end of sequence marker marks discontinuities in the ranges.) */ - if ( lineNo == previousLineNo && ( srcfileindex == previousLineSource ) + if ( lineNo == previousLineNo && strcmp( lineSource, previousLineSource ) == 0 && ! isEndOfSequence ) { /* Don't update the prev* values; just keep going until we hit the end of @@ -4397,12 +4391,18 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) continue; } /* end if we can coalesce this range */ - char *canonicalLineSource = srcfiles[previousLineSource]; + char *canonicalLineSource; if (truncateLineFilenames) { - canonicalLineSource = strrchr( srcfiles[previousLineSource], '/' ); - if( canonicalLineSource == NULL ) { canonicalLineSource = srcfiles[previousLineSource]; } + canonicalLineSource = strrchr( previousLineSource, '/' ); + if( canonicalLineSource == NULL ) { canonicalLineSource = previousLineSource; } else { ++canonicalLineSource; } } + else { + canonicalLineSource = previousLineSource; + } + + + Dyninst::Offset startAddrToUse = previousLineAddr; Dyninst::Offset endAddrToUse = lineAddr; @@ -4428,8 +4428,9 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) isPreviousValid = false; } else { + if( isPreviousValid ) { dwarf_dealloc( dbg, previousLineSource, DW_DLA_STRING ); } previousLineNo = lineNo; - previousLineSource = srcfileindex; + previousLineSource = lineSource; previousLineAddr = lineAddr; previousLineColumn = lineOff; @@ -4439,11 +4440,6 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) /* Free this CU's source lines. */ dwarf_srclines_dealloc(dbg, lineBuffer, lineCount); - for(int i = 0; i < fileCount; ++i) - { - dwarf_dealloc(dbg, srcfiles[i], DW_DLA_STRING); - } - dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST); } From 14f24436129ec7daf2e86dc006c808bdf1fb33cf Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 29 Jul 2016 14:31:24 -0500 Subject: [PATCH 113/180] Cache module DIEs and build ranges as interval trees. --- symtabAPI/h/Function.h | 5 +- symtabAPI/h/Module.h | 16 +++++ symtabAPI/src/Function.C | 4 ++ symtabAPI/src/Module.C | 21 ++++++- symtabAPI/src/Object-elf.C | 107 +++++----------------------------- symtabAPI/src/Object-elf.h | 6 +- symtabAPI/src/Symtab-lookup.C | 6 +- symtabAPI/src/dwarfWalker.C | 34 +++++++---- symtabAPI/src/dwarfWalker.h | 6 +- 9 files changed, 84 insertions(+), 121 deletions(-) diff --git a/symtabAPI/h/Function.h b/symtabAPI/h/Function.h index 3c32c00123..77180021b5 100644 --- a/symtabAPI/h/Function.h +++ b/symtabAPI/h/Function.h @@ -177,8 +177,9 @@ class SYMTAB_EXPORT FunctionBase {return Aggregate::addMangledName(name, isPrimary, isDebug);} virtual bool addPrettyName(std::string name, bool isPrimary, bool isDebug=false) {return Aggregate::addPrettyName(name, isPrimary, isDebug);} - virtual Module* getModule() const { return module_; } -}; + + virtual Module * getModule() const; + }; class SYMTAB_EXPORT InlinedFunction : public FunctionBase { diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index bce04eeebe..81a17d1b0c 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -36,6 +36,10 @@ #include "Annotatable.h" #include "Serialization.h" +#include "IBSTree.h" +#if defined(cap_dwarf) +#include "libdwarf.h" +#endif namespace Dyninst{ namespace SymtabAPI{ @@ -106,6 +110,11 @@ typedef Statement LineNoTuple; class SYMTAB_EXPORT Module : public LookupInterface { +#if defined(cap_dwarf) + typedef Dwarf_Die DebugInfoT; +#else + typedef void* DebugInfoT; +#endif friend class Symtab; public: @@ -193,9 +202,16 @@ typedef Statement LineNoTuple; } bool setLineInfo(Dyninst::SymtabAPI::LineInformation *lineInfo); + void addRange(Dyninst::Address low, Dyninst::Address high); + bool containsOffset(Dyninst::Offset offset) const; + void setDebugInfo(Module::DebugInfoT info) {info_is_valid_ = true; info_ = info; } + Module::DebugInfoT getDebugInfo(); private: Dyninst::SymtabAPI::LineInformation* lineInfo_; typeCollection* typeInfo_; + IBSTree ranges; + bool info_is_valid_; + Module::DebugInfoT info_; std::string fileName_; // short file diff --git a/symtabAPI/src/Function.C b/symtabAPI/src/Function.C index f8f66f65b6..df08cb3ee1 100644 --- a/symtabAPI/src/Function.C +++ b/symtabAPI/src/Function.C @@ -475,3 +475,7 @@ unsigned InlinedFunction::getSize() const { return functionSize_;//inline_parent->getSize(); } + +Module* Function::getModule() const { + return module_; +} \ No newline at end of file diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 676ed06ccb..91dcabb88f 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -303,7 +303,8 @@ Module::Module() : fullName_(""), language_(lang_Unknown), addr_(0), - exec_(NULL) + exec_(NULL), + info_is_valid_(false) { } @@ -315,7 +316,9 @@ Module::Module(const Module &mod) : fullName_(mod.fullName_), language_(mod.language_), addr_(mod.addr_), - exec_(mod.exec_) + exec_(mod.exec_), + info_is_valid_(false), + info_(mod.info_) { } @@ -419,3 +422,17 @@ bool Module::findVariablesByName(std::vector &ret, const std::string return succ; } +void Module::addRange(Dyninst::Address low, Dyninst::Address high) +{ + ranges.insert(new SimpleInterval(low, high, this)); +} + +bool Module::containsOffset(Dyninst::Offset offset) const { + std::set found_entries; + return ranges.find(offset, found_entries) > 0; +} + +Module::DebugInfoT Module::getDebugInfo() +{ + if(!info_is_valid_) exec_->parseTypesNow(); return info_; +} diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 9317a6a93f..2e6fe6e214 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4188,7 +4188,8 @@ void Object::parseStabFileLineInfo(Symtab *st) // haveParsedFileMap[ key ] = true; } /* end parseStabFileLineInfo() */ -bool Object::addrInCU(Dwarf_Debug dbg, Dwarf_Die cu, Address to_check) + +bool Object::addrInCU(Dwarf_Debug dbg, Dwarf_Die cu, Address to_check, Module *mod_for_cu) { Dwarf_Addr tempLow = 0, tempHigh = -1; Address low = 0, high = -1; @@ -4307,11 +4308,13 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) Dwarf_Debug *dbg_ptr = dwarf->line_dbg(); if (!dbg_ptr) return; - Dwarf_Debug &dbg = *dbg_ptr; + if(!cuDIE) return; + Dwarf_Debug dbg = *dbg_ptr; /* Acquire this CU's source lines. */ Dwarf_Line * lineBuffer; Dwarf_Signed lineCount; - int status = dwarf_srclines( cuDIE, & lineBuffer, & lineCount, NULL ); + Dwarf_Error ignored; + int status = dwarf_srclines( cuDIE, & lineBuffer, & lineCount, &ignored ); /* See if we can get anything useful out of the next CU if this one is corrupt. */ @@ -4424,11 +4427,9 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) /* If the current line ends the sequence, invalidate previous; otherwise, update. */ if ( isEndOfSequence ) { - dwarf_dealloc( dbg, lineSource, DW_DLA_STRING ); isPreviousValid = false; } else { - if( isPreviousValid ) { dwarf_dealloc( dbg, previousLineSource, DW_DLA_STRING ); } previousLineNo = lineNo; previousLineSource = lineSource; previousLineAddr = lineAddr; @@ -4451,105 +4452,23 @@ void Object::parseLineInfoForAddr(Symtab* obj, Offset addr_to_find) return; Module* mod_for_offset = NULL; obj->findModuleByOffset(mod_for_offset, addr_to_find); - std::string mod_to_check; if(mod_for_offset) - { if(mod_for_offset->hasLineInformation()) // already parsed { return; } - mod_to_check = mod_for_offset->fileName(); - } - - Dwarf_Debug &dbg = *dbg_ptr; - - /* Only .debug_info for now, not .debug_types */ - Dwarf_Bool is_info = 1; - - /* Itereate over the CU headers. */ - Dwarf_Unsigned header; - while ( dwarf_next_cu_header_c( dbg, is_info, - NULL, NULL, NULL, // len, stamp, abbrev - NULL, NULL, NULL, // address, offset, extension - NULL, NULL, // signature, typeoffset - & header, NULL ) == DW_DLV_OK ) - { - /* Acquire the CU DIE. */ - Dwarf_Die cuDIE; - int status = dwarf_siblingof_b( dbg, NULL, is_info, & cuDIE, NULL); - if ( status != DW_DLV_OK ) { - /* If we can get no (more) CUs, we're done. */ - break; - } - - char * cuName; - const char *moduleName; - status = dwarf_diename( cuDIE, &cuName, NULL ); - if ( status == DW_DLV_NO_ENTRY ) { - cuName = NULL; - moduleName = "DEFAULT_MODULE"; - } - else { - moduleName = strrchr(cuName, '/'); - if (!moduleName) - moduleName = strrchr(cuName, '\\'); - if (moduleName) - moduleName++; - else - moduleName = cuName; - } - if(cuName && modules_parsed_for_line_info.find(cuName) != modules_parsed_for_line_info.end()) - { - dwarf_dealloc(dbg, cuDIE, DW_DLA_DIE); - continue; - } - if(mod_to_check != "" && strcmp(moduleName, mod_to_check.c_str()) != 0) - { - dwarf_dealloc(dbg, cuDIE, DW_DLA_DIE); - continue; - } - // Parse line info for each CU once, completely, if a user has asked for something within - // that CU - if(!addrInCU(dbg, cuDIE, addr_to_find)) - { - dwarf_dealloc(dbg, cuDIE, DW_DLA_DIE); - continue; - } - Module* mod = NULL; - for(auto found_mod = modules_.begin(); - found_mod != modules_.end(); - ++found_mod) - { - if(found_mod->first == moduleName) { - obj->getOrCreateModule(found_mod->first, found_mod->second); - break; - } - } - - if(!obj->findModuleByName(mod, moduleName)) - { - mod = obj->getDefaultModule(); -// cout << "Default module filename is " << mod->fileName() << endl; - } - LineInformation* li_for_module = mod->getLineInformation(); + Dwarf_Die cuDIE = mod_for_offset->getDebugInfo(); + LineInformation* li_for_module = mod_for_offset->getLineInformation(); if(!li_for_module) { li_for_module = new LineInformation; - mod->setLineInfo(li_for_module); - } -// cout << "Parsing line info for " << mod->fileName() << endl; - parseLineInfoForCU(cuDIE, li_for_module); - if (cuName) - { - modules_parsed_for_line_info.insert(cuName); - dwarf_dealloc( dbg, cuName, DW_DLA_STRING ); + mod_for_offset->setLineInfo(li_for_module); } - /* Free this CU's DIE. */ - dwarf_dealloc( dbg, cuDIE, DW_DLA_DIE ); - } /* end CU header iteration */ - /* Note that we've parsed this file. */ + parseLineInfoForCU(cuDIE, li_for_module); + } + // no mod for offset means no line info for sure if we've parsed all ranges... } @@ -4561,7 +4480,7 @@ void Object::parseDwarfFileLineInfo(Symtab* st) Dwarf_Debug *dbg_ptr = dwarf->line_dbg(); if (!dbg_ptr) return; - Dwarf_Debug &dbg = *dbg_ptr; + Dwarf_Debug dbg = *dbg_ptr; /* Only .debug_info for now, not .debug_types */ Dwarf_Bool is_info = 1; diff --git a/symtabAPI/src/Object-elf.h b/symtabAPI/src/Object-elf.h index d6b30391e5..4b39d35f06 100644 --- a/symtabAPI/src/Object-elf.h +++ b/symtabAPI/src/Object-elf.h @@ -522,11 +522,9 @@ class Object; void parseLineInfoForAddr(Symtab* obj, Offset addr_to_find); private: - bool addrInCU(Dwarf_Debug dbg, Dwarf_Die cu, Address to_find); + bool addrInCU(Dwarf_Debug dbg, Dwarf_Die cu, Address to_find, Module *mod_for_cu); void parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li); - - - void createLineInfoForModules(dyn_hash_map &li); + void parseDwarfTypes(Symtab *obj); void parseStabTypes(Symtab *obj); diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 0d014d960b..7831e50c31 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -389,14 +389,10 @@ bool module_less(Module* lhs, Module* rhs) bool Symtab::findModuleByOffset(Module *&ret, Offset off) { - std::sort(_mods.begin(), _mods.end(), module_less); // this should be a hash, really for(size_t i = 0; i < _mods.size(); i++) { -// cout << *(_mods[i]) << endl; - if(_mods[i]->addr() == off) - //&& i < _mods.size() - 1 && - // off < _mods[i+1]->addr()) + if(_mods[i]->containsOffset(off)) { ret = _mods[i]; return true; diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 67d28c8ab3..9c49af291a 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -237,6 +237,7 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { if (!parse_int(moduleDIE, true)) return false; + if(mod()) mod()->setDebugInfo(moduleDIE); return true; @@ -649,6 +650,7 @@ void DwarfWalker::setFuncRanges() { last_high = high; curFunc()->ranges.push_back(FuncRange(low, high - low, curFunc())); + if(mod()) mod()->addRange(low, high); } } } @@ -676,6 +678,7 @@ bool DwarfWalker::parseHighPCLowPC(Dwarf_Die entry) } dwarf_printf("(0x%lx) Lexical block from 0x%lx to 0x%lx\n", id(), low, high); setRange(make_pair(low, high)); + if(mod()) mod()->addRange(low, high); return true; } @@ -709,6 +712,7 @@ bool DwarfWalker::parseRangeTypes() { Address high = cur->dwr_addr2 + cur_base; dwarf_printf("(0x%lx) Lexical block from 0x%lx to 0x%lx\n", id(), low, high); setRange(make_pair(low, high)); + mod()->addRange(low, high); break; } case DW_RANGES_ADDRESS_SELECTION: @@ -1021,8 +1025,11 @@ bool DwarfWalker::parseTypedef() { if (!fixName(curName(), referencedType)) return false; } - typeTypedef * typedefType = new typeTypedef( type_id(), referencedType, curName()); - typedefType = tc()->addOrUpdateType( typedefType ); + if(tc()) + { + typeTypedef * typedefType = new typeTypedef( type_id(), referencedType, curName()); + typedefType = tc()->addOrUpdateType( typedefType ); + } return true; } @@ -1233,16 +1240,20 @@ bool DwarfWalker::parseConstPackedVolatile() { if (!findName(curName())) return false; - Type *type = NULL; - if (!findType(type, true)) return false; - if (!nameDefined()) { - if (!fixName(curName(), type)) return false; - } + if(tc()) + { + Type *type = NULL; + if (!findType(type, true)) return false; - typeTypedef * modifierType = new typeTypedef(type_id(), type, curName()); - assert( modifierType != NULL ); - modifierType = tc()->addOrUpdateType( modifierType ); + if (!nameDefined()) { + if (!fixName(curName(), type)) return false; + } + typeTypedef * modifierType = new typeTypedef(type_id(), type, curName()); + assert( modifierType != NULL ); + modifierType = tc()->addOrUpdateType( modifierType ); + + } return true; } @@ -1273,7 +1284,8 @@ bool DwarfWalker::parseTypeReferences() { return false; } - assert( indirectType != NULL ); + assert( indirectType != NULL ); + } return true; } diff --git a/symtabAPI/src/dwarfWalker.h b/symtabAPI/src/dwarfWalker.h index 8ab7977485..71afe8def1 100644 --- a/symtabAPI/src/dwarfWalker.h +++ b/symtabAPI/src/dwarfWalker.h @@ -401,7 +401,7 @@ namespace Dyninst { virtual void setFuncFromLowest(Address lowest) { m_obj->setModuleForOffset(lowest, modname); - setParseChild(false); + //setParseChild(false); } @@ -418,7 +418,7 @@ namespace Dyninst { } - virtual bool addStaticClassVariable(const std::vector & /*locs*/, Type * /*type*/) { + virtual bool addStaticClassVariable(const std::vector &locs, Type *type) { return false; } @@ -435,7 +435,7 @@ namespace Dyninst { return NULL; } virtual bool parseVariable() { - return false; + return true; } private: Object *m_obj; From 66207c9502e46a68c0a518fe09ae6d6b0a3e02cb Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 29 Jul 2016 14:31:40 -0500 Subject: [PATCH 114/180] Remove dead file from CMakeLists. --- dyninstAPI/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyninstAPI/CMakeLists.txt b/dyninstAPI/CMakeLists.txt index 43f67ae95d..2bf4d60fc7 100644 --- a/dyninstAPI/CMakeLists.txt +++ b/dyninstAPI/CMakeLists.txt @@ -30,7 +30,7 @@ set (SRC_LIST src/BPatch_addressSpace.C src/BPatch_binaryEdit.C src/BPatch_memoryAccess.C - src/dummy.C +# src/dummy.C src/debug.C src/ast.C src/registerSpace.C From 53295edcec494f3d43a2563f622193950e7650a6 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 10 Aug 2016 13:55:40 -0500 Subject: [PATCH 115/180] Initialize DIE to NULL, rather than default constructing, so it's checkable. --- symtabAPI/src/Module.C | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 91dcabb88f..8c67734ccb 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -304,7 +304,8 @@ Module::Module() : language_(lang_Unknown), addr_(0), exec_(NULL), - info_is_valid_(false) + info_is_valid_(false), + info_(NULL) // not a default constructed whatever! { } @@ -434,5 +435,8 @@ bool Module::containsOffset(Dyninst::Offset offset) const { Module::DebugInfoT Module::getDebugInfo() { - if(!info_is_valid_) exec_->parseTypesNow(); return info_; + if(!info_is_valid_) { + exec_->parseTypesNow(); + } + return info_; } From 622956a026a0dbc9d0b35a48a8537fe76cd7a341 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 12 Aug 2016 11:05:35 -0500 Subject: [PATCH 116/180] Many fixes and optimizations--mostly, moving the interval trees for module ranges from one per module to one per symtab with a pointer to the module. --- common/h/IBSTree-fast.h | 44 ++++++++++++++++++++++++++++++----- common/h/IBSTree.h | 2 +- dyninstAPI/src/image.C | 4 ++-- symtabAPI/h/Module.h | 19 +++++++++++---- symtabAPI/h/Symtab.h | 6 ++++- symtabAPI/src/Module.C | 6 +---- symtabAPI/src/Object-elf.C | 17 ++++++++------ symtabAPI/src/Symtab-lookup.C | 30 ++++++++++++++++-------- symtabAPI/src/Symtab.C | 25 +++++++++++--------- symtabAPI/src/dwarfWalker.C | 5 +++- 10 files changed, 110 insertions(+), 48 deletions(-) diff --git a/common/h/IBSTree-fast.h b/common/h/IBSTree-fast.h index de91274098..6de654d378 100644 --- a/common/h/IBSTree-fast.h +++ b/common/h/IBSTree-fast.h @@ -1,22 +1,53 @@ +/* + * 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 + */ +#if !defined(IBSTREE_FAST_H) +#define IBSTREE_FAST_H #include "IBSTree.h" #include #include #include #include -namespace Dyninst +namespace Dyninst { template > class IBSTree_fast { typedef typename ITYPE::type interval_type; - - + IBSTree overlapping_intervals; - typedef boost::multi_index_container > + typedef boost::multi_index_container > > > interval_set; //typedef std::set > interval_set; @@ -153,3 +184,4 @@ namespace Dyninst } +#endif diff --git a/common/h/IBSTree.h b/common/h/IBSTree.h index 6725214965..55ba9be574 100644 --- a/common/h/IBSTree.h +++ b/common/h/IBSTree.h @@ -110,7 +110,7 @@ class SimpleInterval : public interval { virtual int low() const { return low_; } virtual int high() const { return high_; } - private: + protected: int low_; int high_; void * id_; // some arbitrary unique identifier diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index 05bf0ccd63..19afb909bf 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -1699,10 +1699,10 @@ parse_func *image::addFunction(Address functionEntryAddr, const char *fName) } region = *(regions.begin()); // XXX pick one, throwing up hands. - Module* st_mod; + std::set st_mod; linkedFile->findModuleByOffset(st_mod, functionEntryAddr); - pdmodule *mod = getOrCreateModule(st_mod); + pdmodule *mod = getOrCreateModule(*(st_mod.begin())); // copy or create function name char funcName[32]; diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 81a17d1b0c..55be597296 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -37,6 +37,7 @@ #include "Annotatable.h" #include "Serialization.h" #include "IBSTree.h" +#include "IBSTree-fast.h" #if defined(cap_dwarf) #include "libdwarf.h" #endif @@ -203,13 +204,12 @@ typedef Statement LineNoTuple; bool setLineInfo(Dyninst::SymtabAPI::LineInformation *lineInfo); void addRange(Dyninst::Address low, Dyninst::Address high); - bool containsOffset(Dyninst::Offset offset) const; - void setDebugInfo(Module::DebugInfoT info) {info_is_valid_ = true; info_ = info; } + + void setDebugInfo(Module::DebugInfoT info) {info_is_valid_ = true; info_ = info; } Module::DebugInfoT getDebugInfo(); private: Dyninst::SymtabAPI::LineInformation* lineInfo_; typeCollection* typeInfo_; - IBSTree ranges; bool info_is_valid_; Module::DebugInfoT info_; @@ -228,7 +228,18 @@ typedef Statement LineNoTuple; } - +struct ModRange : public interval +{ + ModRange(Offset l, Offset h, Module* m) : + low_(l), high_(h), mod_(m) + {} + Offset low() const { return low_; } + Offset high() const { return high_; } + Module* mod() const { return mod_;} + Offset low_; + Offset high_; + Module* mod_; +}; }//namespace SymtabAPI diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index 17c29f5813..129b20677f 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -84,7 +84,9 @@ class relocationEntry; class Type; class FunctionBase; class FuncRange; +class ModRange; +typedef IBSTree_fast ModRangeLookup; typedef IBSTree FuncRangeLookup; typedef Dyninst::ProcessReader MemRegReader; @@ -198,7 +200,7 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, // Module bool getAllModules(std::vector&ret); - bool findModuleByOffset(Module *&ret, Offset off); + bool findModuleByOffset(std::set& ret, Offset off); bool findModuleByName(Module *&ret, const std::string name); Module *getDefaultModule(); @@ -593,10 +595,12 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, bool isDefensiveBinary_; FuncRangeLookup *func_lookup; + ModRangeLookup *mod_lookup_; //Don't use obj_private, use getObject() instead. public: Object *getObject(); + ModRangeLookup* mod_lookup(); private: Object *obj_private; diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 8c67734ccb..0c44be411d 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -425,12 +425,8 @@ bool Module::findVariablesByName(std::vector &ret, const std::string void Module::addRange(Dyninst::Address low, Dyninst::Address high) { - ranges.insert(new SimpleInterval(low, high, this)); -} -bool Module::containsOffset(Dyninst::Offset offset) const { - std::set found_entries; - return ranges.find(offset, found_entries) > 0; + exec_->mod_lookup()->insert(new ModRange(low, high, this)); } Module::DebugInfoT Module::getDebugInfo() diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 2e6fe6e214..71c5465107 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4450,20 +4450,23 @@ void Object::parseLineInfoForAddr(Symtab* obj, Offset addr_to_find) Dwarf_Debug *dbg_ptr = dwarf->line_dbg(); if (!dbg_ptr) return; - Module* mod_for_offset = NULL; + std::set mod_for_offset; obj->findModuleByOffset(mod_for_offset, addr_to_find); - if(mod_for_offset) + for(auto mod = mod_for_offset.begin(); + mod != mod_for_offset.end(); + ++mod) { - if(mod_for_offset->hasLineInformation()) // already parsed + if((*mod)->hasLineInformation()) // already parsed { - return; + continue; } - Dwarf_Die cuDIE = mod_for_offset->getDebugInfo(); - LineInformation* li_for_module = mod_for_offset->getLineInformation(); + Dwarf_Die cuDIE = ((*mod)->getDebugInfo()); + if(!cuDIE) return; // stashed DIE was null, so we never set it... + LineInformation* li_for_module = ((*mod)->getLineInformation()); if(!li_for_module) { li_for_module = new LineInformation; - mod_for_offset->setLineInfo(li_for_module); + ((*mod)->setLineInfo(li_for_module)); } parseLineInfoForCU(cuDIE, li_for_module); diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 7831e50c31..ef9330bf92 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -387,19 +387,29 @@ bool module_less(Module* lhs, Module* rhs) } -bool Symtab::findModuleByOffset(Module *&ret, Offset off) +bool Symtab::findModuleByOffset(std::set&ret, Offset off) { - // this should be a hash, really - for(size_t i = 0; i < _mods.size(); i++) + std::set mods; + ret.clear(); + mod_lookup()->find(off, mods); + for(auto i = mods.begin(); + i != mods.end(); + ++i) { - if(_mods[i]->containsOffset(off)) - { - ret = _mods[i]; - return true; - } + ret.insert((*i)->mod()); } - ret = NULL; - return false; + return ret.empty(); +// // this should be a hash, really +// for(int i = 0; i < _mods.size(); i++) +// { +// if(_mods[i]->containsOffset(off)) +// { +// ret = _mods[i]; +// return true; +// } +// } +// ret = NULL; +// return false; } bool Symtab::findModuleByName(Module *&ret, const std::string name) diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index 42f600aa62..98abd40c81 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -391,6 +391,7 @@ SYMTAB_EXPORT Symtab::Symtab(MappedFile *mf_) : hasReladyn_(false), hasRelplt_(false), hasRelaplt_(false), isStaticBinary_(false), isDefensiveBinary_(false), func_lookup(NULL), + mod_lookup_(NULL), obj_private(NULL), _ref_cnt(1) { @@ -434,6 +435,7 @@ SYMTAB_EXPORT Symtab::Symtab() : hasReladyn_(false), hasRelplt_(false), hasRelaplt_(false), isStaticBinary_(false), isDefensiveBinary_(false), func_lookup(NULL), + mod_lookup_(NULL), obj_private(NULL), _ref_cnt(1) { @@ -1277,6 +1279,7 @@ Symtab::Symtab(std::string filename, bool defensive_bin, bool &err) : hasReladyn_(false), hasRelplt_(false), hasRelaplt_(false), isStaticBinary_(false), isDefensiveBinary_(defensive_bin), func_lookup(NULL), + mod_lookup_(NULL), obj_private(NULL), _ref_cnt(1) { @@ -1350,6 +1353,7 @@ Symtab::Symtab(unsigned char *mem_image, size_t image_size, isStaticBinary_(false), isDefensiveBinary_(defensive_bin), func_lookup(NULL), + mod_lookup_(NULL), obj_private(NULL), _ref_cnt(1) { @@ -1665,6 +1669,7 @@ Symtab::Symtab(const Symtab& obj) : hasReladyn_(false), hasRelplt_(false), hasRelaplt_(false), isStaticBinary_(false), isDefensiveBinary_(obj.isDefensiveBinary_), func_lookup(NULL), + mod_lookup_(NULL), obj_private(NULL), _ref_cnt(1) { @@ -1862,15 +1867,7 @@ Symtab::~Symtab() // Symbols are copied from linkedFile, and NOT deleted everyDefinedSymbol.clear(); undefDynSyms.clear(); - //undefDynSymsByMangledName.clear(); - //undefDynSymsByPrettyName.clear(); - //undefDynSymsByTypedName.clear(); - // TODO make annotation - //symsByOffset.clear(); - //symsByMangledName.clear(); - //symsByPrettyName.clear(); - //symsByTypedName.clear(); for (unsigned i = 0; i < everyFunction.size(); i++) { @@ -1910,12 +1907,12 @@ Symtab::~Symtab() allSymtabs.erase(allSymtabs.begin()+i); } - if (func_lookup) - delete func_lookup; + delete func_lookup; + delete mod_lookup_; // Make sure to free the underlying Object as it doesn't have a factory // open method - if( obj_private ) delete obj_private; + delete obj_private; if (mf) MappedFile::closeMappedFile(mf); @@ -3803,3 +3800,9 @@ void Symtab::rebase(Offset loadOff) getObject()->rebase(loadOff); load_address_ = loadOff; } + +ModRangeLookup *Symtab::mod_lookup() { + if(!mod_lookup_) mod_lookup_ = new ModRangeLookup; + return mod_lookup_; + +} diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 9c49af291a..f0e9d99376 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -428,7 +428,10 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { DWARF_CHECK_RET(status == DW_DLV_ERROR); /* Deallocate the entry we just parsed. */ - dwarf_dealloc( dbg(), entry(), DW_DLA_DIE ); + if(tag() != DW_TAG_compile_unit) + { + dwarf_dealloc( dbg(), entry(), DW_DLA_DIE ); + } if (status != DW_DLV_OK) { break; From c048f4d2e10a9a122533a5f8e75baa89757f941c Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 15 Aug 2016 14:32:51 -0500 Subject: [PATCH 117/180] Restore old findModuleByOffset interface in parallel with the new one. --- symtabAPI/h/Symtab.h | 1 + symtabAPI/src/Symtab-lookup.C | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index 129b20677f..75faa8baed 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -201,6 +201,7 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, bool getAllModules(std::vector&ret); bool findModuleByOffset(std::set& ret, Offset off); + bool findModuleByOffset(Module *& ret, Offset off); bool findModuleByName(Module *&ret, const std::string name); Module *getDefaultModule(); diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index ef9330bf92..e863918707 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -385,6 +385,16 @@ bool module_less(Module* lhs, Module* rhs) if(rhs == NULL) return true; return lhs->addr() < rhs->addr(); } +bool Symtab::findModuleByOffset(Module *&ret, Offset off) +{ + std::set mods; + mod_lookup()->find(off, mods); + if(!mods.empty()) + { + ret = (*mods.begin())->mod(); + } + return mods.empty(); +} bool Symtab::findModuleByOffset(std::set&ret, Offset off) From 013c69d22803ba64e8b5582c23dc56e7f2dd8ba2 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 16 Aug 2016 13:09:53 -0500 Subject: [PATCH 118/180] Added find and lower_bound to RangeLookup. --- symtabAPI/h/LineInformation.h | 6 +++--- symtabAPI/h/RangeLookup.h | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/symtabAPI/h/LineInformation.h b/symtabAPI/h/LineInformation.h index 8b7a10a3f6..2489f4c2ae 100644 --- a/symtabAPI/h/LineInformation.h +++ b/symtabAPI/h/LineInformation.h @@ -73,11 +73,11 @@ class SYMTAB_EXPORT LineInformation : bool getAddressRanges( const char * lineSource, unsigned int LineNo, std::vector< AddressRange > & ranges ); - const_iterator begin() const; - const_iterator end() const; + virtual const_iterator begin() const; + virtual const_iterator end() const; unsigned getSize() const; - ~LineInformation(); + virtual ~LineInformation(); protected: /* We maintain internal copies of all the source file names. Because diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index 23800f1650..f82d0a7d22 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -102,10 +102,12 @@ class SYMTAB_EXPORT RangeLookup bool getValues( Offset addressInRange, std::vector< Value *> & values ); bool getAddressRanges( Value v, std::vector< AddressRange > & ranges ); - const_iterator begin() const; - const_iterator end() const; + virtual const_iterator begin() const; + virtual const_iterator end() const; + virtual const_iterator find(const AddressRange& ar) const; + virtual const_iterator lower_bound(Offset addr) const; - ~RangeLookup(); + virtual ~RangeLookup(); // /* DEBUG */ void dump( FILE * stream ); // /* DEBUG */ static void testInsertionSpeed(); @@ -474,6 +476,17 @@ RangeLookup< Value, ValueRange >::~RangeLookup() { } /* end RangeLookup destructor */ +template< class Value, class ValueRange > +typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::find(const AddressRange& ar) const +{ + return valuesByAddressRangeMap.find(ar); +} /* end find() */ + +template< class Value, class ValueRange > +typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::lower_bound(Offset addr) const +{ + return valuesByAddressRangeMap.lower_bound(AddressRange(addr, addr)); +} /* end lower_bound() */ } // namespace SymtabAPI } // namespace Dyninst From 1e603c4d6446039a0d04ba527091eb6c80131dda Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 25 Aug 2016 16:32:17 -0500 Subject: [PATCH 119/180] Make interval trees containers --- common/h/IBSTree.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/common/h/IBSTree.h b/common/h/IBSTree.h index 55ba9be574..779e64e12d 100644 --- a/common/h/IBSTree.h +++ b/common/h/IBSTree.h @@ -142,6 +142,7 @@ class IBSNode { ~IBSNode() { } interval_type value() const { return val_; }; + interval_type operator*() const { return value; } private: /* The endpoint of an interval range */ @@ -161,7 +162,15 @@ class IBSNode { template > class IBSTree { +public: typedef typename ITYPE::type interval_type; + typedef IBSNode* iterator; + typedef const IBSNode* const_iterator; + typedef ITYPE value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t difference_type; + typedef size_t size_type; IBSNode *nil; @@ -235,7 +244,18 @@ class IBSTree { delete nil; } - int size() const { return treeSize; } + size_type size() const { return treeSize; } + const_iterator begin() const { + iterator b = root; + while(root->left) b = root->left; + return b; + } + const_iterator end() const { + iterator e = root; + while(root->right) e = root->right; + return e; + + } int CountMarks() const; bool empty() const { return (root == nil); } From 96203bab2a80b41de4ece2f0565cf1d62e6ade3b Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 25 Aug 2016 16:33:54 -0500 Subject: [PATCH 120/180] Gut RangeLookup and replace with boost::multi_index_container as our line information implementation. Still has some obvious performance problems, but appears to work. --- dyninstAPI/h/BPatch_addressSpace.h | 3 +- dyninstAPI/h/BPatch_image.h | 5 +- dyninstAPI/h/BPatch_module.h | 4 +- dyninstAPI/h/BPatch_statement.h | 6 +- dyninstAPI/src/BPatch_addressSpace.C | 2 +- dyninstAPI/src/BPatch_image.C | 2 +- dyninstAPI/src/BPatch_module.C | 12 +- dyninstAPI/src/BPatch_statement.C | 2 +- symtabAPI/h/LineInformation.h | 24 +- symtabAPI/h/Module.h | 29 +- symtabAPI/h/RangeLookup.h | 556 +++++---------------------- symtabAPI/h/Symtab.h | 10 +- symtabAPI/src/LineInformation.C | 134 ++++--- symtabAPI/src/Module.C | 46 +-- symtabAPI/src/Symtab.C | 32 +- 15 files changed, 263 insertions(+), 604 deletions(-) diff --git a/dyninstAPI/h/BPatch_addressSpace.h b/dyninstAPI/h/BPatch_addressSpace.h index 2cce2d0bdc..e33258901e 100644 --- a/dyninstAPI/h/BPatch_addressSpace.h +++ b/dyninstAPI/h/BPatch_addressSpace.h @@ -63,6 +63,7 @@ namespace Dyninst { }; namespace SymtabAPI { class Symbol; + class AddressRange; }; } @@ -318,7 +319,7 @@ class BPATCH_DLL_EXPORT BPatch_addressSpace { // // Method that retrieves address range(s) for a given filename and line number. - bool getAddressRanges(const char * fileName, unsigned int lineNo, std::vector< std::pair< unsigned long, unsigned long > > & ranges ); + bool getAddressRanges(const char * fileName, unsigned int lineNo, std::vector< Dyninst::SymtabAPI::AddressRange> & ranges ); typedef std::vector >::const_iterator arange_iter; statement_iter getAddressRanges_begin(const char* file, unsigned long line); diff --git a/dyninstAPI/h/BPatch_image.h b/dyninstAPI/h/BPatch_image.h index f3d6a07a5e..72e513c9e1 100644 --- a/dyninstAPI/h/BPatch_image.h +++ b/dyninstAPI/h/BPatch_image.h @@ -65,6 +65,9 @@ class BPatch_image; class BPatch_object_getMod; namespace Dyninst { + namespace SymtabAPI { + class AddressRange; + } namespace PatchAPI { class PatchMgr; typedef boost::shared_ptr PatchMgrPtr; @@ -242,7 +245,7 @@ class BPATCH_DLL_EXPORT BPatch_image: public BPatch_sourceObj { // method to retrieve addresses corresponding to a line in a file bool getAddressRanges( const char * fileName, unsigned int lineNo, - std::vector > & ranges ); + std::vector & ranges ); bool getSourceLines( unsigned long addr, BPatch_Vector & lines ); diff --git a/dyninstAPI/h/BPatch_module.h b/dyninstAPI/h/BPatch_module.h index f99cebe13d..33014112e5 100644 --- a/dyninstAPI/h/BPatch_module.h +++ b/dyninstAPI/h/BPatch_module.h @@ -62,6 +62,7 @@ class BPatch_object; namespace Dyninst { namespace SymtabAPI { class Module; + class AddressRange; BPATCH_DLL_EXPORT Module *convert(const BPatch_module *); } namespace PatchAPI { @@ -230,7 +231,8 @@ class BPATCH_DLL_EXPORT BPatch_module: public BPatch_sourceObj{ // function to get addresses for a line of the module // if fileName is NULL, uses the name of the module - bool getAddressRanges( const char * fileName, unsigned int lineNo, std::vector< std::pair< unsigned long, unsigned long > > & ranges ); + bool getAddressRanges(const char *fileName, unsigned int lineNo, + std::vector &ranges); // BPatch_module::getSourceLines // diff --git a/dyninstAPI/h/BPatch_statement.h b/dyninstAPI/h/BPatch_statement.h index 242dce1ebb..b4a434d4b9 100644 --- a/dyninstAPI/h/BPatch_statement.h +++ b/dyninstAPI/h/BPatch_statement.h @@ -32,12 +32,14 @@ #define _BPATCH_STATEMENT_H_ #include "BPatch_dll.h" +#include class BPatch_module; namespace Dyninst { namespace SymtabAPI { class Statement; + typedef boost::shared_ptr StatementConstPtr; } } @@ -79,10 +81,10 @@ class BPATCH_DLL_EXPORT BPatch_statement private: // Full parameter ctor -- can only built by friend classes - BPatch_statement(BPatch_module *mod, Dyninst::SymtabAPI::Statement *s); + BPatch_statement(BPatch_module *mod, Dyninst::SymtabAPI::StatementConstPtr s); BPatch_module *module_; - Dyninst::SymtabAPI::Statement *statement; + Dyninst::SymtabAPI::StatementConstPtr statement; }; #endif diff --git a/dyninstAPI/src/BPatch_addressSpace.C b/dyninstAPI/src/BPatch_addressSpace.C index 37a0e59c2b..22153841a2 100644 --- a/dyninstAPI/src/BPatch_addressSpace.C +++ b/dyninstAPI/src/BPatch_addressSpace.C @@ -538,7 +538,7 @@ bool BPatch_addressSpace::revertWrapFunction(BPatch_function *original) bool BPatch_addressSpace::getAddressRanges( const char * fileName, unsigned int lineNo, - std::vector< std::pair< unsigned long, unsigned long > > & ranges ) + std::vector< SymtabAPI::AddressRange > & ranges ) { unsigned int originalSize = ranges.size(); image->getAddressRanges(fileName, lineNo, ranges); diff --git a/dyninstAPI/src/BPatch_image.C b/dyninstAPI/src/BPatch_image.C index 3113d9327c..f5e34e2c7f 100644 --- a/dyninstAPI/src/BPatch_image.C +++ b/dyninstAPI/src/BPatch_image.C @@ -872,7 +872,7 @@ bool BPatch_image::getSourceLines(unsigned long addr, bool BPatch_image::getAddressRanges( const char * lineSource, unsigned int lineNo, - std::vector< std::pair > & ranges ) + std::vector< SymtabAPI::AddressRange > & ranges ) { unsigned int originalSize = ranges.size(); diff --git a/dyninstAPI/src/BPatch_module.C b/dyninstAPI/src/BPatch_module.C index d08e51da13..4e430bfcc3 100644 --- a/dyninstAPI/src/BPatch_module.C +++ b/dyninstAPI/src/BPatch_module.C @@ -678,7 +678,7 @@ bool BPatch_module::getSourceLines(unsigned long addr, } unsigned int originalSize = lines.size(); - std::vector lines_ll; + std::vector lines_ll; Module *stmod = mod->pmod()->mod(); assert(stmod); @@ -690,7 +690,7 @@ bool BPatch_module::getSourceLines(unsigned long addr, for (unsigned int j = 0; j < lines_ll.size(); ++j) { - Statement *t = lines_ll[j]; + Statement::ConstPtr t = lines_ll[j]; lines.push_back(BPatch_statement(this, t)); } @@ -702,7 +702,7 @@ bool BPatch_module::getStatements(BPatch_Vector &statements) // Iterate over each address range in the line information SymtabAPI::Module *stmod = mod->pmod()->mod(); assert(stmod); - std::vector statements_ll; + std::vector statements_ll; if (!stmod->getStatements(statements_ll)) { @@ -714,7 +714,7 @@ bool BPatch_module::getStatements(BPatch_Vector &statements) // Form a BPatch_statement object for this entry // Note: Line information stores offsets, so we need to adjust to // addresses - SymtabAPI::Statement *stm = statements_ll[i]; + SymtabAPI::Statement::ConstPtr stm = statements_ll[i]; BPatch_statement statement(this, stm); // Add this statement @@ -725,8 +725,8 @@ bool BPatch_module::getStatements(BPatch_Vector &statements) } -bool BPatch_module::getAddressRanges( const char * fileName, - unsigned int lineNo, std::vector< std::pair< Address, Address > > & ranges ) +bool BPatch_module::getAddressRanges(const char *fileName, + unsigned int lineNo, std::vector &ranges) { unsigned int starting_size = ranges.size(); diff --git a/dyninstAPI/src/BPatch_statement.C b/dyninstAPI/src/BPatch_statement.C index d8d6fd809d..b2997ff03a 100644 --- a/dyninstAPI/src/BPatch_statement.C +++ b/dyninstAPI/src/BPatch_statement.C @@ -33,7 +33,7 @@ #include "Module.h" #include "mapped_object.h" #include "mapped_module.h" -BPatch_statement::BPatch_statement(BPatch_module *mod, Dyninst::SymtabAPI::Statement *s) : +BPatch_statement::BPatch_statement(BPatch_module *mod, Dyninst::SymtabAPI::Statement::ConstPtr s) : module_(mod), statement(s) { diff --git a/symtabAPI/h/LineInformation.h b/symtabAPI/h/LineInformation.h index 2489f4c2ae..25bc77de14 100644 --- a/symtabAPI/h/LineInformation.h +++ b/symtabAPI/h/LineInformation.h @@ -43,13 +43,15 @@ namespace Dyninst{ namespace SymtabAPI{ class SYMTAB_EXPORT LineInformation : - private RangeLookup< Statement, Statement::StatementLess > + private RangeLookupTypes< Statement >::type { bool addItem_impl(Statement); public: - typedef RangeLookup< Statement, Statement::StatementLess >::const_iterator const_iterator; - typedef RangeLookup< Statement, Statement::StatementLess >::AddressRange AddressRange; - + typedef RangeLookupTypes< Statement> traits; + typedef RangeLookupTypes< Statement >::type impl_t; + typedef traits::addr_range_index::const_iterator const_iterator; + typedef traits::line_info_index::const_iterator const_line_info_iterator; + typedef traits::value_type Statement_t; LineInformation(); /* You MAY freely deallocate the lineSource strings you pass in. */ @@ -68,13 +70,19 @@ class SYMTAB_EXPORT LineInformation : unsigned int lineOffset = 0 ); /* You MUST NOT deallocate the strings returned. */ - bool getSourceLines( Offset addressInRange, std::vector< Statement *> & lines ); - bool getSourceLines( Offset addressInRange, std::vector< LineNoTuple > & lines); + bool getSourceLines(Offset addressInRange, std::vector &lines); + bool getSourceLines(Offset addressInRange, std::vector &lines); bool getAddressRanges( const char * lineSource, unsigned int LineNo, std::vector< AddressRange > & ranges ); + const_line_info_iterator begin_by_source() const; + const_line_info_iterator end_by_source() const; + std::pair equal_range(std::string file, + const unsigned int lineNo) const; + std::pair equal_range(std::string file) const; + const_iterator begin() const; + const_iterator end() const; + const_iterator find(Offset addressInRange) const; - virtual const_iterator begin() const; - virtual const_iterator end() const; unsigned getSize() const; virtual ~LineInformation(); diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 55be597296..9cd7e97a58 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -41,6 +41,8 @@ #if defined(cap_dwarf) #include "libdwarf.h" #endif +#include +#include "RangeLookup.h" namespace Dyninst{ namespace SymtabAPI{ @@ -50,12 +52,12 @@ class LineInformation; class localVar; class Symtab; + class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable { friend class Module; friend class std::vector; friend class LineInformation; - Statement(const char *file, unsigned int line, unsigned int col = 0, Offset start_addr = (Offset) -1L, Offset end_addr = (Offset) -1L) : file_(file), @@ -88,14 +90,17 @@ class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable typedef StatementLess LineNoTupleLess; bool operator==(const Statement &cmp) const; + bool operator==(const char* file) const {return strcmp(file, first) == 0; } + bool operator==(Offset addr) const {return startAddr() <= addr && addr < endAddr(); } ~Statement() {} - Offset startAddr() { return start_addr_;} - Offset endAddr() {return end_addr_;} - std::string getFile() { return file_;} - unsigned int getLine() {return line_;} - unsigned int getColumn() {return column;} - + Offset startAddr() const { return start_addr_;} + Offset endAddr() const {return end_addr_;} + std::string getFile() const { return file_;} + unsigned int getLine()const {return line_;} + unsigned int getColumn() const{return column;} + AddressRange addressRange( ) const { return AddressRange(*this); } + bool contains(Offset addr) const { return addressRange().contains(addr); } Serializable *serialize_impl(SerializerBase *sb, const char *tag = "Statement") THROW_SPEC (SerializerError); // Does dyninst really need these? @@ -104,6 +109,8 @@ class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable void setFile(const char * l) {file_ = l; first = file_;} void setStartAddr(Offset l) {start_addr_ = l;} void setEndAddr(Offset l) {end_addr_ = l;} + typedef boost::shared_ptr Ptr; + typedef boost::shared_ptr ConstPtr; }; typedef Statement LineNoTuple; @@ -182,15 +189,15 @@ typedef Statement LineNoTuple; bool findLocalVariable(std::vector&vars, std::string name); /***** Line Number Information *****/ - bool getAddressRanges(std::vector >&ranges, + bool getAddressRanges(std::vector&ranges, std::string lineSource, unsigned int LineNo); - bool getSourceLines(std::vector &lines, + bool getSourceLines(std::vector &lines, Offset addressInRange); bool getSourceLines(std::vector &lines, Offset addressInRange); - bool getStatements(std::vector &statements); + bool getStatements(std::vector &statements); LineInformation *getLineInformation(); - + LineInformation* parseLineInformation(); bool hasLineInformation(); bool setDefaultNamespacePrefix(std::string str); diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index f82d0a7d22..aa42729b80 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -37,457 +37,105 @@ #include #include "dyntypes.h" #include "util.h" - - -namespace Dyninst -{ -namespace SymtabAPI -{ - -/* The Windows C++ compiler is broken and won't instantiate this function when it's in RangeLookup proper. */ - -class SYMTAB_EXPORT RangeLookupImpl -{ - public: - typedef std::pair< Offset, Offset > AddressRange; - - /* Explicit comparison functors seems slightly less confusing than using - operator <() via an implicit Less<> template argument to the maps. */ - - struct AddressRangeLess { - bool operator()(const AddressRange &lhs, const AddressRange &rhs) const - { - if ( lhs.first < rhs.first ) - { - return true; - } - else if ( lhs.first == rhs.first ) - { - if ( lhs.second < rhs.second ) - { - return true; - } - else - { - return false; - } - } - - return false; - } /* end AddressRangeLess() */ - }; - -}; /* end class RangeLookupImpl */ - -template< class Value, class ValueLess > -class SYMTAB_EXPORT RangeLookup -{ - protected: - typedef RangeLookupImpl::AddressRange AddressRange; - typedef RangeLookupImpl::AddressRangeLess AddressRangeLess; - - typedef std::multimap< Value, AddressRange, ValueLess > AddressRangeByValue; - typedef std::multimap< AddressRange, Value, AddressRangeLess > ValueByAddressRange; - - public: - typedef typename ValueByAddressRange::const_iterator const_iterator; - - RangeLookup(); - - /* Values are copied: a RangeLookup considers itself the primary repository. */ - bool addValue( Value v, Offset lowInclusiveAddr, Offset highExclusiveAddr ); - bool addAddressRange( Offset lowInclusiveAddr, Offset highExclusiveAddr, Value v ); - - /* Likewise, copies of the values are returned. */ - bool getValues( Offset addressInRange, std::vector< Value *> & values ); - bool getAddressRanges( Value v, std::vector< AddressRange > & ranges ); - - virtual const_iterator begin() const; - virtual const_iterator end() const; - virtual const_iterator find(const AddressRange& ar) const; - virtual const_iterator lower_bound(Offset addr) const; - - virtual ~RangeLookup(); - - // /* DEBUG */ void dump( FILE * stream ); - // /* DEBUG */ static void testInsertionSpeed(); - - protected: - ValueByAddressRange valuesByAddressRangeMap; - AddressRangeByValue addressRangesByValueMap; -}; /* end class RangeLookup */ - -template< class Value, class ValueRange > RangeLookup< Value, ValueRange >::RangeLookup() : - valuesByAddressRangeMap(), - addressRangesByValueMap() {} - -/* Private refactoring function: erase()s value from map. */ -template< class M > -bool removeByValue( M & map, const typename M::value_type & value ) -{ - std::pair< typename M::iterator, typename M::iterator > range = map.equal_range( value.first ); -#if 0 -#if ! defined( os_windows ) - std::pair< typename M::iterator, typename M::iterator > range = map.equal_range( value.first ); -#else - std::pair< M::iterator, M::iterator > range = map.equal_range( value.first ); -#endif -#endif - - for ( ; range.first != range.second && range.first != map.end(); ++range.first ) - { - typename M::value_type &cmp = *range.first; - if (cmp == value ) - { - map.erase( range.first ); - return true; - } - } - - return false; - -} /* end removeByValue() */ - -/* We maintain the invariant that low and high address sort orders are the same. (If we - didn't, we could only find one of the two endpoints of the range of ranges we should - check. If we find one endpoint and iterate over the other sort order until we found - the other, a range contained by another range would change the sort order and cause - ranges containing the search target to be skippped.) So we check, whenever we insert - a new range, if it contains or is contained by any other range. - - Since we insert elements one at a time, we can assume that no range already present - contains another range. Furthermore, if no range contains another range, then any - range (B) between the inserted range (I) and a range which might contain it (A) - must also contain I. (Where ranges are ordered by their low address.) - - (Proof by contradiction: suppose there exists a B not containing I. Because B is between - I and A, B's low address is lower than I's. Therefore, because B does not contain I, its - high address must be lower than I's. Because I is contained by A, its high address is - lower than A's. By transitivity, B's high address is lower than A's. Since B's low - address is higher than A's (because B is between A and I), B is contained by A. Contradiction.) - - Therefore, we only need to check ranges lower than I until one of them does not contain it. - If we split each containing range in the middle of I, we can insert I and maintain our - no-overlap invariant. - - Similar logic applies in reverse direction: if I contains a range, it contains every - range between it and I. - - Furthermore, the same range can't be both contained and contained-by: if it's contained-by, - its container contains whatever it does. - - We want to split ranges so that their low and high addresses sort in the same order. (Strictly - speaking, the above conditions ought to be "not a range which will cause the low and high address - sort order to be different, but it ends up not mattering, AFAICT.) - - If we're inserting a contained range, we split the containing ranges on the contained range's right edge. - - If we're inserted a containing range, we split it and the other ranges on the least upper address in - each group of contained ranges. - */ - -template -bool RangeLookup< Value, ValueRange >::addValue(Value v, - Offset lowInclusiveAddr, - Offset highExclusiveAddr) -{ - /* Verify the input. */ - if ( lowInclusiveAddr >= highExclusiveAddr ) - { - return false; - } - - /* If we've already got this range, it's safe to insert it. */ - - typedef typename ValueByAddressRange::iterator RangeIterator; - std::pair< RangeIterator, RangeIterator > rangeOfRanges; - - rangeOfRanges = valuesByAddressRangeMap.equal_range(AddressRange(lowInclusiveAddr, - highExclusiveAddr)); - - if ( (rangeOfRanges.first != rangeOfRanges.second) - || (valuesByAddressRangeMap.size() == 0) ) - { - // insert() is amortized constant time if the new value is inserted - // immediately before the hint. - valuesByAddressRangeMap.insert( rangeOfRanges.second, - std::make_pair(AddressRange(lowInclusiveAddr, - highExclusiveAddr), v)); - - addressRangesByValueMap.insert( std::make_pair( v, AddressRange(lowInclusiveAddr, - highExclusiveAddr))); - return true; - } - - /* Otherwise, we need to look for containing ranges. */ - - typedef std::pair< AddressRange, Value > Range; - typedef std::list< Range > RangeList; - RangeIterator downIterator = rangeOfRanges.second; - - if (rangeOfRanges.second != valuesByAddressRangeMap.begin()) - { - --downIterator; - } - - RangeList containingRangeList; - for (; ( (downIterator->first.first <= lowInclusiveAddr) - && (highExclusiveAddr < downIterator->first.second) ) - ; --downIterator ) - { - - containingRangeList.push_back( * downIterator ); - - if ( downIterator == valuesByAddressRangeMap.begin() ) - break; - } - - /* We also need to look for contained ranges. */ - RangeIterator upIterator = rangeOfRanges.second; - RangeList containedRangeList; - - for (; (upIterator != valuesByAddressRangeMap.end()) - && ((lowInclusiveAddr <= upIterator->first.first) - && (upIterator->first.second < highExclusiveAddr) ) - ; ++upIterator ) - { - - containedRangeList.push_back( * upIterator ); - } /* end iteration looking for contained ranges */ - - if (containingRangeList.size() == 0 && containedRangeList.size() == 0 ) - { - /* insert() is amortized constant time if the new value is inserted immediately before the hint. */ - valuesByAddressRangeMap.insert(rangeOfRanges.second, - std::make_pair(AddressRange(lowInclusiveAddr, - highExclusiveAddr), v)); - addressRangesByValueMap.insert( std::make_pair(v,AddressRange(lowInclusiveAddr, - highExclusiveAddr))); - return true; - } - - /* TODO: combine lists; if wasContaining, splitaddrlist is just highExclusiveAddr */ - - if (containingRangeList.size() != 0) - { - Offset splitAddress = highExclusiveAddr; - - /* Remove the old (containing) ranges, split them, insert the new ones. */ - typename RangeList::const_iterator containingIterator = containingRangeList.begin(); - - for ( ; containingIterator != containingRangeList.end(); ++containingIterator ) - { - AddressRange ar = containingIterator->first; - Value lnt = containingIterator->second; - - // These could be out of sync, though I'm not sure how. We know that - // values by address range has what we're looking for, because we've got - // an iterator; the converse is not automatically true. So check that remove - // first. Furthermore, bail with "return false" rather than asserting. - if(!(removeByValue( addressRangesByValueMap, std::make_pair( lnt, ar ) )) || - !(removeByValue( valuesByAddressRangeMap, * containingIterator ))) - { - return false; - - } - //assert( removeByValue( valuesByAddressRangeMap, * containingIterator ) ); - //assert( removeByValue( addressRangesByValueMap, std::make_pair( lnt, ar ) ) ); - - valuesByAddressRangeMap.insert(std::make_pair(AddressRange(ar.first, - splitAddress), lnt)); - addressRangesByValueMap.insert( std::make_pair(lnt,AddressRange(ar.first, - splitAddress))); - - valuesByAddressRangeMap.insert(std::make_pair(AddressRange(splitAddress, - ar.second ), lnt ) ); - addressRangesByValueMap.insert(std::make_pair(lnt, AddressRange(splitAddress, - ar.second ) ) ); - } /* end removes/split/insert iteration */ - - /* Insert the new range. */ - valuesByAddressRangeMap.insert(std::make_pair(AddressRange(lowInclusiveAddr, - highExclusiveAddr ), v ) ); - addressRangesByValueMap.insert(std::make_pair(v, AddressRange(lowInclusiveAddr, - highExclusiveAddr ) ) ); - return true; - } /* end if the range to be inserted is contained by other ranges. */ - - if (containedRangeList.size() != 0 ) - { - /* We'll split the ranges at these points. */ - typedef std::list< Offset > AddressList; - AddressList splitAddressList; - - /* Overlapping ranges overlap until a discontuity, so we only need to - know about one of them. */ - - typename RangeList::const_iterator containedIterator = containedRangeList.begin(); - Offset splitAddress = containedIterator->first.second; - ++containedIterator; - - for ( ; containedIterator != containedRangeList.end(); ++containedIterator ) - { - /* Is there a discontinuity? */ - - if (containedIterator->first.first >= splitAddress) - { - /* If there is, our current splitAddress should be a split, */ - splitAddressList.push_back( splitAddress ); - - /* and the high end of the next contained range will be our next split point. */ - splitAddress = containedIterator->first.second; - } - else - { - splitAddress = containedIterator->first.second; - } - } /* end split point determination iteration */ - - splitAddressList.push_back( splitAddress ); - - /* Split the range to be inserted. */ - - Offset lowAddress = lowInclusiveAddr; - AddressList::const_iterator splitAddressIterator = splitAddressList.begin(); - Offset highAddress = 0; - - for ( ; splitAddressIterator != splitAddressList.end(); ++ splitAddressIterator ) - { - highAddress = * splitAddressIterator; - - valuesByAddressRangeMap.insert(std::make_pair(AddressRange(lowAddress, highAddress ), v ) ); - addressRangesByValueMap.insert(std::make_pair(v, AddressRange(lowAddress, highAddress ) ) ); - - lowAddress = highAddress; - } /* end iteration to split range to be inserted. */ - - valuesByAddressRangeMap.insert(std::make_pair(AddressRange( highAddress, highExclusiveAddr ), v ) ); - addressRangesByValueMap.insert(std::make_pair(v, AddressRange( highAddress, highExclusiveAddr ) ) ); - - /* We done did it. */ - return true; - } /* end if the range to be inserted contains other ranges. */ - - /* Something Terrible happened. */ - return false; -} /* end addValue() */ - -template< class Value, class ValueRange > -bool RangeLookup< Value, ValueRange >::addAddressRange( Offset lowInclusiveAddr, - Offset highExclusiveAddr, - Value v ) -{ - return addValue( v, lowInclusiveAddr, highExclusiveAddr ); -} /* end addAddressRange() */ - - -/* We maintain the invariant that the ranges sort in the same order on - their low and high addresses. In this case, we only need to search from - the range whose low address is the least too large down to the range - whose high address is the first too small to find all ranges which - contain the desired address. - */ -template< class Value, class ValueRange > -bool RangeLookup< Value, ValueRange >::getValues( Offset addressInRange, - std::vector< Value *> & values ) -{ - /* We can't find an address if we have no ranges. */ - if ( valuesByAddressRangeMap.size() == 0 ) - return false; - - /* Because the sort order of the low and high addresses is the same, we know every range - which could contain addressInRange must be below the range whose low address is one - larger, and above the range whose high address is the same. We use addressInRange + 1 - to make sure we find one past the end of a span of ranges with the same low address, - so we decrement the iterator to point it at the first range which could contain - addressInRange. If equal_range() returns end(), then decrementing the iterator - ensures we start checking with a real range. */ - - typedef typename ValueByAddressRange::const_iterator RangeIterator; - std::pair< RangeIterator, RangeIterator > lowRange - = valuesByAddressRangeMap.equal_range( AddressRange( addressInRange + 1, 0 ) ); - - if (lowRange.second == valuesByAddressRangeMap.begin()) - return false; //Searched for an address lower than any in the map. - - assert( lowRange.first == lowRange.second ); - RangeIterator hHighEnd = --(lowRange.second); - - /* Some implementations get stuck on valuesByAddressRangeMap.begin(), apparently. */ - - for ( ; hHighEnd->first.second > addressInRange && hHighEnd != valuesByAddressRangeMap.end(); - --hHighEnd ) - { - if ( (hHighEnd->first.first <= addressInRange) - && (addressInRange < hHighEnd->first.second) ) - { - values.push_back( const_cast (& hHighEnd->second) ); - } - - if (hHighEnd == valuesByAddressRangeMap.begin() ) - break; - } /* end iteration over possible range matches. */ - - if ( values.size() == 0 ) - return false; - - return true; -} /* end getLinesFromAddress() */ - -template< class Value, class ValueRange > -bool RangeLookup< Value, ValueRange >::getAddressRanges(Value v, - std::vector &ranges) -{ - /* Look for the specified lineSource:lineNo. */ - typedef typename AddressRangeByValue::const_iterator IteratorType; - std::pair< IteratorType, IteratorType > range = addressRangesByValueMap.equal_range( v ); - - /* If equal_range() doesn't find anything, range.first and range.second will be equal. */ - - if ( range.first == range.second ) - { - return false; - } - - /* Otherwise, copy out the found ranges. */ - for ( IteratorType i = range.first; i != range.second; ++i ) - { - // ranges.push_back( AddressRange(i->second)); - ranges.push_back(i->second); - } /* end iteration over located address ranges. */ - - return true; -} /* end getAddressRangesFromLine() */ - -template< class Value, class ValueRange > -typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::begin() const -{ - return valuesByAddressRangeMap.begin(); -} /* end begin() */ - -template< class Value, class ValueRange > -typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::end() const -{ - return valuesByAddressRangeMap.end(); -} /* end begin() */ - -template< class Value, class ValueRange > -RangeLookup< Value, ValueRange >::~RangeLookup() -{ -} /* end RangeLookup destructor */ - -template< class Value, class ValueRange > -typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::find(const AddressRange& ar) const -{ - return valuesByAddressRangeMap.find(ar); -} /* end find() */ - -template< class Value, class ValueRange > -typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::lower_bound(Offset addr) const -{ - return valuesByAddressRangeMap.lower_bound(AddressRange(addr, addr)); -} /* end lower_bound() */ - -} // namespace SymtabAPI -} // namespace Dyninst -#endif +#include +#include +#include +#include +#include +#include +#include + + +namespace Dyninst { + namespace SymtabAPI { + + struct SYMTAB_EXPORT AddressRange : std::pair + { + template + AddressRange(T t) { + first = t.startAddr(); + second = t.endAddr(); + } + AddressRange(Offset t) + { + first = t; + second = t; + } + bool operator==(const AddressRange& rhs) const { + return first == rhs.first && second == rhs.second; + } + bool operator<(const AddressRange& rhs) const { + return first < rhs.first || (first == rhs.first && second < rhs.second); + } + bool contains(Offset off) const { + return first <= off && off < second; + } + + }; + template + struct RangeLookupTypes + { + struct addr_range {}; + struct line_info {}; + typedef typename boost::multi_index::const_mem_fun addr_range_key; + typedef typename boost::multi_index::composite_key, + boost::multi_index::const_mem_fun > line_info_key; + typedef typename boost::multi_index_container + < + typename Value::ConstPtr, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< boost::multi_index::tag, addr_range_key>, + boost::multi_index::ordered_non_unique< boost::multi_index::tag, line_info_key > + > + > type; + typedef typename boost::multi_index::index::type addr_range_index; + typedef typename boost::multi_index::index::type line_info_index; + typedef typename type::value_type value_type; + + + }; + +// template +// class SYMTAB_EXPORT RangeLookup : public RangeLookupIndexTypes::Values { +// +// public: +// typedef std::pair AddressRange; +// typedef typename RangeLookupIndexTypes::Values parent; +// RangeLookup(); +// +// /* Values are copied: a RangeLookup considers itself the primary repository. */ +// bool addValue(Value v) { +// parent::insert(v); +// return true; +// } +// +// /* Likewise, copies of the values are returned. */ +// bool getValues(Offset addressInRange, std::vector &values) { +// auto by_addr_range = parent::get<0>(); +// auto found = by_addr_range.equal_range(addressInRange); +// std::copy(found.first, found.second, std::back_inserter(values)); +// return found.first != found.second; +// } +// template +// bool getAddressRanges(const char* lineSource, int lineNo, _OI out_iter) const { +// auto &by_line_info = parent::get<1>(); +// if(lineNo <= 0) // wildcard it +// { +// auto lines = by_line_info.equal_range(lineSource); +// std::copy(lines.first, lines.second, out_iter); +// return lines.first != lines.second; +// } +// auto lines = by_line_info.equal_range(lineSource, lineNo); +// std::copy(lines.first, lines.second, out_iter); +// return lines.first != lines.second; +// +// } +// virtual ~RangeLookup(); +// +// +// }; /* end class RangeLookup */ + + } +} +#endif \ No newline at end of file diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index 75faa8baed..ed75df3d33 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -253,11 +253,11 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, bool getMappedRegions(std::vector &mappedRegs) const; /***** Line Number Information *****/ - bool getAddressRanges(std::vector >&ranges, - std::string lineSource, unsigned int LineNo); - bool getSourceLines(std::vector &lines, - Offset addressInRange); - bool getSourceLines(std::vector &lines, + bool getAddressRanges(std::vector &ranges, + std::string lineSource, unsigned int LineNo); + bool getSourceLines(std::vector &lines, + Offset addressInRange); + bool getSourceLines(std::vector &lines, Offset addressInRange); bool addLine(std::string lineSource, unsigned int lineNo, unsigned int lineOffset, Offset lowInclAddr, diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 1e2baacfef..a105be31cf 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -28,7 +28,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "LineInformation.h" #include #include #include @@ -37,22 +36,23 @@ #include "Module.h" #include "Serialization.h" +#include + using namespace Dyninst; using namespace Dyninst::SymtabAPI; -using namespace std; +using std::vector; + +#include "LineInformation.h" -LineInformation::LineInformation() : - Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >() +LineInformation::LineInformation() { - size_ = 0; } /* end LineInformation constructor */ bool LineInformation::addItem_impl(Statement s) { - size_++; - - bool ret = addValue( s, s.startAddr(), s.endAddr() ); - return ret; + insert(Statement::ConstPtr(new Statement(s))); +// insert(s); + return true; } bool LineInformation::addLine( const char * lineSource, unsigned int lineNo, @@ -61,6 +61,7 @@ bool LineInformation::addLine( const char * lineSource, Offset highExclusiveAddr ) { + bool ret = addItem_impl( Statement(lineSource, lineNo, lineOffset, lowInclusiveAddr, highExclusiveAddr)); @@ -69,13 +70,9 @@ bool LineInformation::addLine( const char * lineSource, void LineInformation::addLineInfo(LineInformation *lineInfo) { - const_iterator iter = lineInfo->begin(); - - for (; iter != lineInfo->end(); iter++) - { - addLine(iter->second.file_, iter->second.line_, iter->second.column, - iter->first.first, iter->first.second); - } + if(!lineInfo) + return; + insert(lineInfo->begin(), lineInfo->end()); } bool LineInformation::addAddressRange( Offset lowInclusiveAddr, @@ -87,84 +84,93 @@ bool LineInformation::addAddressRange( Offset lowInclusiveAddr, return addLine( lineSource, lineNo, lineOffset, lowInclusiveAddr, highExclusiveAddr ); } /* end setAddressRangeToLineMapping() */ -bool LineInformation::getSourceLines( Offset addressInRange, - vector< Statement *> & lines ) +bool LineInformation::getSourceLines(Offset addressInRange, + vector &lines) { - return getValues( addressInRange, lines ); + using namespace std::placeholders; + auto start_addr_valid = lower_bound(addressInRange + 1); + std::copy_if(begin(), + start_addr_valid, + std::back_inserter(lines), + std::bind(&Statement::contains, std::placeholders::_1, addressInRange)); + return start_addr_valid != begin(); } /* end getLinesFromAddress() */ -bool LineInformation::getSourceLines( Offset addressInRange, - vector &lines) +bool LineInformation::getSourceLines( Offset addressInRange, + vector &lines) { - vector plines; - bool result = getValues(addressInRange, plines); - if (!result) { - return false; - } - for (vector::iterator i = plines.begin(); i != plines.end(); i++) { - LineNoTuple lnt = **i; - lines.push_back(lnt); - } - return true; + vector tmp; + if(!getSourceLines(addressInRange, tmp)) return false; + for(auto i = tmp.begin(); i != tmp.end(); ++i) + { + lines.push_back(**i); + } + return true; } /* end getLinesFromAddress() */ + + bool LineInformation::getAddressRanges( const char * lineSource, unsigned int lineNo, vector< AddressRange > & ranges ) { - bool ret = Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >::getAddressRanges( Statement( lineSource, lineNo ), ranges ); - - return ret; + auto found_statements = equal_range(lineSource, lineNo); + std::transform(found_statements.first, found_statements.second, + std::back_inserter(ranges), + std::mem_fn(&Statement::addressRange)); + return found_statements.first != found_statements.second; } /* end getAddressRangesFromLine() */ LineInformation::const_iterator LineInformation::begin() const { - return Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >::begin(); + return impl_t::begin(); } /* end begin() */ LineInformation::const_iterator LineInformation::end() const { - return Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >::end(); -} /* end begin() */ + return impl_t::end(); +} /* end end() */ + +LineInformation::const_iterator LineInformation::find(Offset addressInRange) const +{ + return impl_t::find(addressInRange); +} /* end find() */ + + unsigned LineInformation::getSize() const { - return size_; + return impl_t::size(); } -bool Statement::StatementLess::operator () ( const Statement &lhs, const Statement &rhs ) const -{ - // dont bother with ordering by column information yet. - int strcmp_res = strcmp( lhs.file_, rhs.file_); - if (strcmp_res < 0 ) - return true; +LineInformation::~LineInformation() +{ +} - if ( strcmp_res == 0 ) - { - if ( lhs.line_ < rhs.line_ ) - return true; - } +LineInformation::const_line_info_iterator LineInformation::begin_by_source() const { + const traits::line_info_index& i = get(); + return i.begin(); +} - return false; -} /* end StatementLess() */ +LineInformation::const_line_info_iterator LineInformation::end_by_source() const { + const traits::line_info_index& i = get(); + return i.end(); +} -bool Statement::operator==(const Statement &cmp) const -{ - if (line_ != cmp.line_) return false; - if (column != cmp.column) return false; +std::pair +LineInformation::equal_range(std::string file, const unsigned int lineNo) const { + return get().equal_range(std::make_tuple(file, lineNo)); - // is compare-by-pointer OK here, or do we really have to really strcmp? - return (file_ == cmp.file_); } -/* We free the strings we allocated, and let the compiler clean up everything else: +std::pair +LineInformation::equal_range(std::string file) const { + return get().equal_range(file); +// const traits::line_info_index& by_line_info = impl_t::get(); +// return by_line_info.equal_range(file); - Section 10.4.6 [Stroustroup's C++]: "When a class object containing class - objects is destroyed, the body of that object's own destructor is executed first, - and then the members' destructors are executed in the reverse order of declaration." */ +} -LineInformation::~LineInformation() -{ -} /* end LineInformation destructor */ +/* end LineInformation destructor */ diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 0c44be411d..5f7843f5ec 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -123,12 +123,12 @@ bool Module::hasLineInformation() return lineInfo_ && lineInfo_->getSize(); } -bool Module::getAddressRanges(std::vector >&ranges, +bool Module::getAddressRanges(std::vector&ranges, std::string lineSource, unsigned int lineNo) { unsigned int originalSize = ranges.size(); - LineInformation *lineInformation = getLineInformation(); + LineInformation *lineInformation = parseLineInformation(); if (lineInformation) lineInformation->getAddressRanges( lineSource.c_str(), lineNo, ranges ); @@ -138,15 +138,11 @@ bool Module::getAddressRanges(std::vector >&ranges, return false; } -bool Module::getSourceLines(std::vector &lines, Offset addressInRange) +bool Module::getSourceLines(std::vector &lines, Offset addressInRange) { unsigned int originalSize = lines.size(); - LineInformation *lineInformation = getLineInformation(); - if(!lineInformation) { - exec_->parseLineInformation(); - lineInformation = getLineInformation(); - } + LineInformation *lineInformation = parseLineInformation(); // cout << "Module " << fileName() << " searching for line info in " << lineInformation << endl; if (lineInformation) lineInformation->getSourceLines( addressInRange, lines ); @@ -161,11 +157,7 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan { unsigned int originalSize = lines.size(); - LineInformation *lineInformation = getLineInformation(); - if(!lineInformation) { - exec_->parseLineInformation(); - lineInformation = getLineInformation(); - } + LineInformation *lineInformation = parseLineInformation(); // cout << "Module " << fileName() << " searching for line info in " << lineInformation << endl; if (lineInformation) @@ -177,23 +169,23 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan return false; } -bool Module::getStatements(std::vector &statements) +LineInformation *Module::parseLineInformation() { + LineInformation *lineInformation = getLineInformation(); + if (!lineInformation) + { + exec_->parseLineInformation(); + lineInformation = getLineInformation(); + return lineInformation; + } +} + +bool Module::getStatements(std::vector &statements) { unsigned initial_size = statements.size(); - LineInformation *li = getLineInformation(); - if (!li) - { - exec_->parseLineInformation(); - li = getLineInformation(); - if(!li) return false; - } + LineInformation *li = parseLineInformation(); + if(!li) return false; - for (LineInformation::const_iterator i = li->begin(); - i != li->end(); - ++i) - { - statements.push_back(const_cast(&(i->second))); - } + std::copy(li->begin(), li->end(), std::back_inserter(statements)); return (statements.size() > initial_size); } diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index 98abd40c81..fa443dde7e 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -2307,8 +2307,8 @@ void Symtab::parseLineInformation() linkedFile->parseFileLineInfo(this); } -SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector >&ranges, - std::string lineSource, unsigned int lineNo) +SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector &ranges, + std::string lineSource, unsigned int lineNo) { unsigned int originalSize = ranges.size(); parseLineInformation(); @@ -2329,7 +2329,7 @@ SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector >&r return false; } -SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) +SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) { unsigned int originalSize = lines.size(); @@ -2354,24 +2354,14 @@ SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offse SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) { - unsigned int originalSize = lines.size(); - - getObject()->parseLineInfoForAddr(this, addressInRange); - - /* Iteratate over the modules, looking for ranges in each. */ - for ( unsigned int i = 0; i < _mods.size(); i++ ) - { - LineInformation *lineInformation = _mods[i]->getLineInformation(); - - if (lineInformation) - lineInformation->getSourceLines( addressInRange, lines ); - - } /* end iteration over modules */ - - if ( lines.size() != originalSize ) - return true; - - return false; + std::vector tmp; + getSourceLines(tmp, addressInRange); + if(tmp.empty()) return false; + for(auto i = tmp.begin(); i != tmp.end(); ++i) + { + lines.push_back(**i); + } + return true; } SYMTAB_EXPORT bool Symtab::addLine(std::string lineSource, unsigned int lineNo, From 0dee1c8f86df8c898b3f86418b30f75326b5fc89 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 26 Aug 2016 17:46:21 -0500 Subject: [PATCH 121/180] Lots of refactoring and some optimizations. We're not saving space or time anymore but at least it's clean and we're only missing ~10k entries (down from ~100k) on nwchem. --- symtabAPI/h/LineInformation.h | 3 +- symtabAPI/h/Module.h | 28 +++-- symtabAPI/h/RangeLookup.h | 24 +++- symtabAPI/src/LineInformation.C | 41 +++++-- symtabAPI/src/Module.C | 47 ++++---- symtabAPI/src/Object-elf.C | 205 ++------------------------------ symtabAPI/src/Object-elf.h | 5 +- symtabAPI/src/Object.h | 4 +- symtabAPI/src/Symtab.C | 32 +++-- symtabAPI/src/dwarfWalker.C | 22 +++- 10 files changed, 147 insertions(+), 264 deletions(-) diff --git a/symtabAPI/h/LineInformation.h b/symtabAPI/h/LineInformation.h index 25bc77de14..c479081151 100644 --- a/symtabAPI/h/LineInformation.h +++ b/symtabAPI/h/LineInformation.h @@ -94,7 +94,8 @@ class SYMTAB_EXPORT LineInformation : (in the destructor). Note that it speeds and simplifies things to have the string pointers be the same. */ - unsigned size_; + int wasted_compares; + int num_queries; }; /* end class LineInformation */ }//namespace SymtabAPI diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 9cd7e97a58..dd80b827bc 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -53,7 +53,7 @@ class localVar; class Symtab; -class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable +class SYMTAB_EXPORT Statement// : public AnnotatableSparse, public Serializable { friend class Module; friend class std::vector; @@ -101,7 +101,6 @@ class SYMTAB_EXPORT Statement : public AnnotatableSparse, public Serializable unsigned int getColumn() const{return column;} AddressRange addressRange( ) const { return AddressRange(*this); } bool contains(Offset addr) const { return addressRange().contains(addr); } - Serializable *serialize_impl(SerializerBase *sb, const char *tag = "Statement") THROW_SPEC (SerializerError); // Does dyninst really need these? void setLine(unsigned int l) {line_ = l;} @@ -118,14 +117,14 @@ typedef Statement LineNoTuple; class SYMTAB_EXPORT Module : public LookupInterface { + friend class Symtab; + + public: #if defined(cap_dwarf) typedef Dwarf_Die DebugInfoT; #else typedef void* DebugInfoT; #endif - friend class Symtab; - - public: Module(); Module(supportedLanguages lang, Offset adr, std::string fullNm, @@ -198,8 +197,8 @@ typedef Statement LineNoTuple; bool getStatements(std::vector &statements); LineInformation *getLineInformation(); LineInformation* parseLineInformation(); - bool hasLineInformation(); - bool setDefaultNamespacePrefix(std::string str); + + bool setDefaultNamespacePrefix(std::string str); // Super secret private methods that aren't really private @@ -212,13 +211,12 @@ typedef Statement LineNoTuple; bool setLineInfo(Dyninst::SymtabAPI::LineInformation *lineInfo); void addRange(Dyninst::Address low, Dyninst::Address high); - void setDebugInfo(Module::DebugInfoT info) {info_is_valid_ = true; info_ = info; } - Module::DebugInfoT getDebugInfo(); - private: + void setDebugInfo(Module::DebugInfoT info); + + private: Dyninst::SymtabAPI::LineInformation* lineInfo_; typeCollection* typeInfo_; - bool info_is_valid_; - Module::DebugInfoT info_; + std::vector info_; std::string fileName_; // short file @@ -233,6 +231,12 @@ typedef Statement LineNoTuple; os << m.fileName() << ": " << m.addr(); return os; } + template + OS& operator<<(OS& os, Module* m) + { + os << m->fileName() << ": " << m->addr(); + return os; + } struct ModRange : public interval diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index aa42729b80..cc86a9836d 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -61,14 +61,19 @@ namespace Dyninst { first = t; second = t; } + AddressRange(Offset start, Offset end) + { + first = start; + second = end; + } bool operator==(const AddressRange& rhs) const { - return first == rhs.first && second == rhs.second; + return (first == rhs.first) && (second == rhs.second); } bool operator<(const AddressRange& rhs) const { - return first < rhs.first || (first == rhs.first && second < rhs.second); + return (first < rhs.first) || ((first == rhs.first) && (second < rhs.second)); } bool contains(Offset off) const { - return first <= off && off < second; + return (first <= off) && (off < second); } }; @@ -77,19 +82,28 @@ namespace Dyninst { { struct addr_range {}; struct line_info {}; - typedef typename boost::multi_index::const_mem_fun addr_range_key; + struct upper_bound {}; + typedef typename boost::multi_index::const_mem_fun + addr_range_key; + typedef typename boost::multi_index::composite_key, + boost::multi_index::const_mem_fun > + upper_bound_key; typedef typename boost::multi_index::composite_key, - boost::multi_index::const_mem_fun > line_info_key; + boost::multi_index::const_mem_fun > + line_info_key; typedef typename boost::multi_index_container < typename Value::ConstPtr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag, addr_range_key>, + boost::multi_index::ordered_non_unique< boost::multi_index::tag, upper_bound_key>, boost::multi_index::ordered_non_unique< boost::multi_index::tag, line_info_key > > > type; typedef typename boost::multi_index::index::type addr_range_index; + typedef typename boost::multi_index::index::type upper_bound_index; typedef typename boost::multi_index::index::type line_info_index; typedef typename type::value_type value_type; diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index a105be31cf..467bba62e3 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -37,6 +37,7 @@ #include "Serialization.h" #include +#include using namespace Dyninst; using namespace Dyninst::SymtabAPI; @@ -44,7 +45,7 @@ using std::vector; #include "LineInformation.h" -LineInformation::LineInformation() +LineInformation::LineInformation() : wasted_compares(0), num_queries(0) { } /* end LineInformation constructor */ @@ -84,16 +85,35 @@ bool LineInformation::addAddressRange( Offset lowInclusiveAddr, return addLine( lineSource, lineNo, lineOffset, lowInclusiveAddr, highExclusiveAddr ); } /* end setAddressRangeToLineMapping() */ + +std::string print(const Dyninst::SymtabAPI::Statement& stmt) +{ + std::stringstream stream; + stream << "Statement: < [" << stmt.startAddr() << ", " << stmt.endAddr() << "): " << stmt.getFile() << ":" << stmt.getLine() << " >"; + return stream.str(); +} + + bool LineInformation::getSourceLines(Offset addressInRange, vector &lines) { - using namespace std::placeholders; - auto start_addr_valid = lower_bound(addressInRange + 1); - std::copy_if(begin(), - start_addr_valid, - std::back_inserter(lines), - std::bind(&Statement::contains, std::placeholders::_1, addressInRange)); - return start_addr_valid != begin(); + ++num_queries; + const_iterator start_addr_valid = project(get().upper_bound(addressInRange )); + const_iterator end_addr_valid = impl_t::upper_bound(addressInRange + 1); + while(start_addr_valid != end_addr_valid) + { + if((*start_addr_valid)->contains(addressInRange)) + { + lines.push_back(*start_addr_valid); + } + else + { + std::cout << print(**start_addr_valid) << " does not contain " << addressInRange << std::endl; + ++wasted_compares; + } + ++start_addr_valid; + } + return true; } /* end getLinesFromAddress() */ bool LineInformation::getSourceLines( Offset addressInRange, @@ -146,6 +166,11 @@ unsigned LineInformation::getSize() const LineInformation::~LineInformation() { + if(num_queries) + { + std::cout << "Line information with " << getSize() << " entries queried " << num_queries << " times with " + << wasted_compares << " extra compares (" << (float)(wasted_compares) / (num_queries) << " per query)" << std::endl; + } } LineInformation::const_line_info_iterator LineInformation::begin_by_source() const { diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 5f7843f5ec..9ab7472cfa 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -29,6 +29,8 @@ */ #include +#include +#include "debug.h" #include "Annotatable.h" #include "Module.h" @@ -42,6 +44,7 @@ #include "common/src/pathName.h" #include "common/src/serialize.h" +#include "Object.h" #if defined(cap_dwarf) #include "dwarfWalker.h" @@ -118,11 +121,6 @@ supportedLanguages Module::language() const return language_; } -bool Module::hasLineInformation() -{ - return lineInfo_ && lineInfo_->getSize(); -} - bool Module::getAddressRanges(std::vector&ranges, std::string lineSource, unsigned int lineNo) { @@ -143,7 +141,6 @@ bool Module::getSourceLines(std::vector &lines, Offset addr unsigned int originalSize = lines.size(); LineInformation *lineInformation = parseLineInformation(); -// cout << "Module " << fileName() << " searching for line info in " << lineInformation << endl; if (lineInformation) lineInformation->getSourceLines( addressInRange, lines ); @@ -170,13 +167,20 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan } LineInformation *Module::parseLineInformation() { - LineInformation *lineInformation = getLineInformation(); - if (!lineInformation) + // if non-null, we're fine + if (!lineInfo_) { - exec_->parseLineInformation(); - lineInformation = getLineInformation(); - return lineInformation; + lineInfo_ = new LineInformation; } +// cout << "Parsing line info for module:" << *this << " with " << info_.size() << " CU entries set" << endl; + for(auto cu = info_.begin(); + cu != info_.end(); + ++cu) + { + exec()->getObject()->parseLineInfoForCU(*cu, lineInfo_); + } + info_.clear(); + return lineInfo_; } bool Module::getStatements(std::vector &statements) @@ -245,8 +249,10 @@ bool Module::findVariableType(Type *&type, std::string name) bool Module::setLineInfo(LineInformation *lineInfo) { - lineInfo_ = lineInfo; - return true; + assert(!lineInfo_); + //delete lineInfo_; + lineInfo_ = lineInfo; + return true; } LineInformation *Module::getLineInformation() @@ -295,9 +301,7 @@ Module::Module() : fullName_(""), language_(lang_Unknown), addr_(0), - exec_(NULL), - info_is_valid_(false), - info_(NULL) // not a default constructed whatever! + exec_(NULL) { } @@ -310,7 +314,6 @@ Module::Module(const Module &mod) : language_(mod.language_), addr_(mod.addr_), exec_(mod.exec_), - info_is_valid_(false), info_(mod.info_) { } @@ -417,14 +420,10 @@ bool Module::findVariablesByName(std::vector &ret, const std::string void Module::addRange(Dyninst::Address low, Dyninst::Address high) { - exec_->mod_lookup()->insert(new ModRange(low, high, this)); } -Module::DebugInfoT Module::getDebugInfo() -{ - if(!info_is_valid_) { - exec_->parseTypesNow(); - } - return info_; +void Module::setDebugInfo(Module::DebugInfoT info) { +// cout << "Adding DIE to module:" << *this << endl; + info_.push_back(info); } diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 71c5465107..b2b565ccfe 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4189,119 +4189,6 @@ void Object::parseStabFileLineInfo(Symtab *st) } /* end parseStabFileLineInfo() */ -bool Object::addrInCU(Dwarf_Debug dbg, Dwarf_Die cu, Address to_check, Module *mod_for_cu) -{ - Dwarf_Addr tempLow = 0, tempHigh = -1; - Address low = 0, high = -1; - Dwarf_Bool has_attr; - Dwarf_Error please_ignore; // malformed dwarf can spew errors on lowpc and highpc; we'll use this to swallow those (as they're handled safely) - // and not leak memory with a bad error handler. - if(dwarf_hasattr(cu, DW_AT_low_pc, &has_attr, NULL) != DW_DLV_OK) return false; - if(has_attr) - { - if(dwarf_hasattr(cu, DW_AT_high_pc, &has_attr, NULL) != DW_DLV_OK) return false; - if(has_attr) - { - int status = dwarf_lowpc(cu, &tempLow, &please_ignore); - if(status == DW_DLV_OK) - { - low = (Address) tempLow; - //cerr << "lowpc/highpc, low is " << hex << low << ", addr is " << to_check << endl; - if(low > to_check) return false; - status = dwarf_highpc(cu, &tempHigh, NULL);//&please_ignore); - if(status == DW_DLV_OK) - { - high = (Address) tempHigh; - //cerr << "lowpc/highpc, high is " << hex << high << ", addr is " << to_check << endl; - - if(to_check < high) return true; - } - else if(status == DW_DLV_ERROR) - { - // this is most likely a case where libdwarf doesn't handle dwarf4. - // claim the address is in this CU; better to overparse. - return true; - //cerr << "lowpc/highpc, high threw error" << endl; - // dwarf_dealloc(dbg, please_ignore, DW_DLA_ERROR); - } - } - } - } - - Dwarf_Bool hasRanges = false; - if(dwarf_hasattr(cu, DW_AT_ranges, &hasRanges, NULL) != DW_DLV_OK) { - //cerr << "no lowpc/highpc, error getting ranges\n"; - return false; - } - - if (hasRanges) { - Address range_offset = 0; - Dwarf_Attribute off_attr; - Dwarf_Half off_form; - - if(dwarf_attr(cu, DW_AT_ranges, &off_attr, NULL) != DW_DLV_OK) return false; - if(dwarf_whatform(off_attr, &off_form, NULL) != DW_DLV_OK) return false; - switch(off_form) - { - case DW_FORM_addr: - Dwarf_Addr a; - if(dwarf_formaddr(off_attr, &a, NULL) != DW_DLV_OK) return false; - range_offset = Address(a); - break; - case DW_FORM_sdata: - Dwarf_Signed sd; - if(dwarf_formsdata(off_attr, &sd, NULL) != DW_DLV_OK) return false; - range_offset = Address(sd); - break; - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - case DW_FORM_udata: - Dwarf_Unsigned u; - if(dwarf_formudata(off_attr, &u, NULL) != DW_DLV_OK) return false; - range_offset = Address(u); - break; - case DW_FORM_sec_offset: - if(dwarf_global_formref(off_attr, &u, NULL) != DW_DLV_OK) return false; - range_offset = Address(u); - break; - } - - Dwarf_Ranges *ranges = NULL; - Dwarf_Signed ranges_length = 0; - if(dwarf_get_ranges_a(dbg, (Dwarf_Off) range_offset, cu, - &ranges, &ranges_length, NULL, NULL) != DW_DLV_OK) return false; - - - bool done = false; - Address cur_base = low; - for (unsigned i = 0; i < ranges_length && !done; i++) { - Dwarf_Ranges *cur = ranges + i; - switch (cur->dwr_type) { - case DW_RANGES_ENTRY: { - Address curlow = cur->dwr_addr1 + cur_base; - Address curhigh = cur->dwr_addr2 + cur_base; - - if(curlow <= to_check && to_check < curhigh) return true; - - break; - } - case DW_RANGES_ADDRESS_SELECTION: - cur_base = cur->dwr_addr2; - break; - case DW_RANGES_END: - done = true; - break; - } - } - dwarf_dealloc(dbg, off_attr, DW_DLA_ATTR); - dwarf_ranges_dealloc(dbg, ranges, ranges_length); - } - return false; -} - - void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) { @@ -4456,20 +4343,7 @@ void Object::parseLineInfoForAddr(Symtab* obj, Offset addr_to_find) mod != mod_for_offset.end(); ++mod) { - if((*mod)->hasLineInformation()) // already parsed - { - continue; - } - Dwarf_Die cuDIE = ((*mod)->getDebugInfo()); - if(!cuDIE) return; // stashed DIE was null, so we never set it... - LineInformation* li_for_module = ((*mod)->getLineInformation()); - if(!li_for_module) - { - li_for_module = new LineInformation; - ((*mod)->setLineInfo(li_for_module)); - } - - parseLineInfoForCU(cuDIE, li_for_module); + (*mod)->parseLineInformation(); } // no mod for offset means no line info for sure if we've parsed all ranges... } @@ -4480,77 +4354,14 @@ void Object::parseLineInfoForAddr(Symtab* obj, Offset addr_to_find) // Dwarf Debug Format parsing void Object::parseDwarfFileLineInfo(Symtab* st) { - Dwarf_Debug *dbg_ptr = dwarf->line_dbg(); - if (!dbg_ptr) - return; - Dwarf_Debug dbg = *dbg_ptr; - - /* Only .debug_info for now, not .debug_types */ - Dwarf_Bool is_info = 1; - - /* Itereate over the CU headers. */ - Dwarf_Unsigned header; - while ( dwarf_next_cu_header_c( dbg, is_info, - NULL, NULL, NULL, // len, stamp, abbrev - NULL, NULL, NULL, // address, offset, extension - NULL, NULL, // signature, typeoffset - & header, NULL ) == DW_DLV_OK ) + vector mods; + st->getAllModules(mods); + for(auto mod = mods.begin(); + mod != mods.end(); + ++mod) { - /* Acquire the CU DIE. */ - Dwarf_Die cuDIE; - int status = dwarf_siblingof_b( dbg, NULL, is_info, & cuDIE, NULL); - if ( status != DW_DLV_OK ) { - /* If we can get no (more) CUs, we're done. */ - break; - } - - char * cuName; - const char *moduleName; - status = dwarf_diename( cuDIE, &cuName, NULL ); - if ( status == DW_DLV_NO_ENTRY ) { - cuName = NULL; - moduleName = "DEFAULT_MODULE"; - } - else { - moduleName = strrchr(cuName, '/'); - if (!moduleName) - moduleName = strrchr(cuName, '\\'); - if (moduleName) - moduleName++; - else - moduleName = cuName; - } - Module* mod = NULL; -// for(auto found_mod = modules_.begin(); -// found_mod != modules_.end(); -// ++found_mod) -// { -// if(found_mod->first == moduleName) { -// mod = st->getOrCreateModule(found_mod->first, found_mod->second); -// break; -// } -// } - if(!st->findModuleByName(mod, moduleName)) { - mod = st->getDefaultModule(); -// cout << "Default module is " << mod->fileName() <getDefaultModule(); - LineInformation* li_for_module = mod->getLineInformation(); - if(!li_for_module) - { - li_for_module = new LineInformation; - mod->setLineInfo(li_for_module); - } -// cout << "Parsing line info for " <fileName() <parseLineInformation(); + } } /* end parseDwarfFileLineInfo() */ void Object::parseFileLineInfo(Symtab *st) diff --git a/symtabAPI/src/Object-elf.h b/symtabAPI/src/Object-elf.h index 4b39d35f06..35882edee5 100644 --- a/symtabAPI/src/Object-elf.h +++ b/symtabAPI/src/Object-elf.h @@ -262,12 +262,14 @@ class Region; class Object; class Object : public AObject { + friend class Module; // declared but not implemented; no copying allowed Object(const Object &); const Object& operator=(const Object &); public: + Object(MappedFile *, bool, void (*)(const char *) = log_msg, bool alloc_syms = true); virtual ~Object(); @@ -522,8 +524,7 @@ class Object; void parseLineInfoForAddr(Symtab* obj, Offset addr_to_find); private: - bool addrInCU(Dwarf_Debug dbg, Dwarf_Die cu, Address to_find, Module *mod_for_cu); - void parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li); + void parseLineInfoForCU(Module::DebugInfoT cuDIE, LineInformation* li); void parseDwarfTypes(Symtab *obj); void parseStabTypes(Symtab *obj); diff --git a/symtabAPI/src/Object.h b/symtabAPI/src/Object.h index c1c191e18b..07e13e0600 100644 --- a/symtabAPI/src/Object.h +++ b/symtabAPI/src/Object.h @@ -135,7 +135,8 @@ class AObject { SYMTAB_EXPORT bool hasError() const; SYMTAB_EXPORT virtual bool isBigEndianDataEncoding() const { return false; } SYMTAB_EXPORT virtual bool getABIVersion(int & /*major*/, int & /*minor*/) const { return false; } - + + virtual void setTruncateLinePaths(bool value); virtual bool getTruncateLinePaths(); virtual Region::RegionType getRelType() const { return Region::RT_INVALID; } @@ -147,6 +148,7 @@ class AObject { SYMTAB_EXPORT virtual ~AObject(); // explicitly protected SYMTAB_EXPORT AObject(MappedFile *, void (*err_func)(const char *)); + virtual void parseLineInfoForCU(Module::DebugInfoT module_debug_info, LineInformation* li) { } MappedFile *mf; diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index fa443dde7e..9fb739ac25 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -2333,21 +2333,33 @@ SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &line { unsigned int originalSize = lines.size(); - getObject()->parseLineInfoForAddr(this, addressInRange); - /* Iteratate over the modules, looking for ranges in each. */ - for ( unsigned int i = 0; i < _mods.size(); i++ ) - { - LineInformation *lineInformation = _mods[i]->getLineInformation(); - - if (lineInformation) - lineInformation->getSourceLines( addressInRange, lines ); - - } /* end iteration over modules */ + std::set mods_for_offset; + findModuleByOffset(mods_for_offset, addressInRange); + for(auto i = mods_for_offset.begin(); + i != mods_for_offset.end(); + ++i) + { + std::cout << "Checking module " << (*(*i)) << " for " << addressInRange << endl; + (*i)->getSourceLines(lines, addressInRange); + } +// /* Iteratate over the modules, looking for ranges in each. */ +// for ( unsigned int i = 0; i < _mods.size(); i++ ) +// { +// LineInformation *lineInformation = _mods[i]->getLineInformation(); +// +// if (lineInformation) +// lineInformation->getSourceLines( addressInRange, lines ); +// +// } /* end iteration over modules */ if ( lines.size() != originalSize ) return true; + if(!mods_for_offset.empty()) { + std::cout << "WARNING: Modules have ranges for 0x" << std::hex << addressInRange << " but lack line info"<< std::endl; + std::copy(mods_for_offset.begin(), mods_for_offset.end(), std::ostream_iterator(std::cout, "\n")); + } return false; } diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index f0e9d99376..309da5329f 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -225,8 +225,14 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { if (findConstant(DW_AT_high_pc, tempModHigh, entry(), dbg())) { modHigh = convertDebugOffset(tempModHigh); } - - setModuleFromName(moduleName); + // We have enough info to make a new module if we have a low address. + if(modLow && symtab()) + { + mod() = symtab()->getOrCreateModule(moduleName, modLow); + } else + { + setModuleFromName(moduleName); + } //dwarf_printf("Mapped to Symtab module %s\n", mod()->fileName().c_str()); @@ -234,10 +240,16 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { fixUnknownMod = mod(); if (!buildSrcFiles(moduleDIE)) return false; + if(mod()) { + mod()->setDebugInfo(moduleDIE); + if(modLow && modHigh) + { + mod()->addRange(modLow, modHigh); + } + } if (!parse_int(moduleDIE, true)) return false; - if(mod()) mod()->setDebugInfo(moduleDIE); return true; @@ -428,7 +440,9 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { DWARF_CHECK_RET(status == DW_DLV_ERROR); /* Deallocate the entry we just parsed. */ - if(tag() != DW_TAG_compile_unit) + if(tag() != DW_TAG_compile_unit && + tag() != DW_TAG_partial_unit && + tag() != DW_TAG_type_unit) { dwarf_dealloc( dbg(), entry(), DW_DLA_DIE ); } From 4e4a375a4f4cf143792dcd26c59e3a9cd3a16ce0 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 1 Sep 2016 14:33:21 -0500 Subject: [PATCH 122/180] Line info fixes: nwchem is now running clean. There's a good bit of room for performance improvements (notably in ensuring that we don't have redundant module intervals). --- cmake/warnings.cmake | 2 +- dyninstAPI/src/BPatch_module.C | 4 +- symtabAPI/h/LineInformation.h | 24 +++- symtabAPI/h/Module.h | 88 ++++++++---- symtabAPI/h/RangeLookup.h | 4 +- symtabAPI/h/StringTable.h | 41 ++++++ symtabAPI/h/Symtab.h | 2 +- symtabAPI/src/LineInformation.C | 54 +++++--- symtabAPI/src/Module.C | 83 ++++++++++-- symtabAPI/src/Object-elf.C | 232 +++++++++++++++++++++++--------- symtabAPI/src/Object-elf.h | 16 +-- symtabAPI/src/Object-nt.C | 15 +-- symtabAPI/src/Object-nt.h | 13 +- symtabAPI/src/Object.C | 5 +- symtabAPI/src/Object.h | 5 +- symtabAPI/src/Symtab.C | 66 ++++----- symtabAPI/src/dwarfWalker.C | 129 +++++++++--------- symtabAPI/src/dwarfWalker.h | 14 +- 18 files changed, 524 insertions(+), 273 deletions(-) create mode 100644 symtabAPI/h/StringTable.h diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake index 864697ccb4..d32b97d3ea 100644 --- a/cmake/warnings.cmake +++ b/cmake/warnings.cmake @@ -1,6 +1,6 @@ if (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_C_COMPILER_ID} MATCHES INTEL) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Wcast-align") -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual -Wcast-align -Wno-non-template-friend -Wno-unused-local-typedefs") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual -Wcast-align -Wno-non-template-friend -Wno-unused-local-typedefs -Wno-deprecated-declarations") elseif (${CMAKE_C_COMPILER_ID} MATCHES Clang) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual") diff --git a/dyninstAPI/src/BPatch_module.C b/dyninstAPI/src/BPatch_module.C index 4e430bfcc3..d39c088f50 100644 --- a/dyninstAPI/src/BPatch_module.C +++ b/dyninstAPI/src/BPatch_module.C @@ -678,7 +678,7 @@ bool BPatch_module::getSourceLines(unsigned long addr, } unsigned int originalSize = lines.size(); - std::vector lines_ll; + std::vector lines_ll; Module *stmod = mod->pmod()->mod(); assert(stmod); @@ -702,7 +702,7 @@ bool BPatch_module::getStatements(BPatch_Vector &statements) // Iterate over each address range in the line information SymtabAPI::Module *stmod = mod->pmod()->mod(); assert(stmod); - std::vector statements_ll; + std::vector statements_ll; if (!stmod->getStatements(statements_ll)) { diff --git a/symtabAPI/h/LineInformation.h b/symtabAPI/h/LineInformation.h index c479081151..0a05dd4b4d 100644 --- a/symtabAPI/h/LineInformation.h +++ b/symtabAPI/h/LineInformation.h @@ -45,8 +45,7 @@ namespace SymtabAPI{ class SYMTAB_EXPORT LineInformation : private RangeLookupTypes< Statement >::type { - bool addItem_impl(Statement); - public: +public: typedef RangeLookupTypes< Statement> traits; typedef RangeLookupTypes< Statement >::type impl_t; typedef traits::addr_range_index::const_iterator const_iterator; @@ -55,11 +54,16 @@ class SYMTAB_EXPORT LineInformation : LineInformation(); /* You MAY freely deallocate the lineSource strings you pass in. */ - bool addLine( const char * lineSource, + bool addLine( std::string lineSource, unsigned int lineNo, unsigned int lineOffset, Offset lowInclusiveAddr, Offset highExclusiveAddr ); + bool addLine( unsigned int fileIndex, + unsigned int lineNo, + unsigned int lineOffset, + Offset lowInclusiveAddr, + Offset highExclusiveAddr ); void addLineInfo(LineInformation *lineInfo); @@ -94,9 +98,19 @@ class SYMTAB_EXPORT LineInformation : (in the destructor). Note that it speeds and simplifies things to have the string pointers be the same. */ - int wasted_compares; + StringTablePtr strings_; +public: + StringTablePtr getStrings() ; + + void setStrings(StringTablePtr strings_); + +protected: + int wasted_compares; int num_queries; -}; /* end class LineInformation */ +}; + + + /* end class LineInformation */ }//namespace SymtabAPI }//namespace Dyninst diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index dd80b827bc..6a6864d1ca 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -44,6 +44,8 @@ #include #include "RangeLookup.h" +#include "StringTable.h" + namespace Dyninst{ namespace SymtabAPI{ @@ -53,36 +55,34 @@ class localVar; class Symtab; -class SYMTAB_EXPORT Statement// : public AnnotatableSparse, public Serializable +class SYMTAB_EXPORT Statement { friend class Module; - friend class std::vector; friend class LineInformation; - Statement(const char *file, unsigned int line, unsigned int col = 0, + Statement(int file_index, unsigned int line, unsigned int col = 0, Offset start_addr = (Offset) -1L, Offset end_addr = (Offset) -1L) : - file_(file), + file_index_(file_index), line_(line), + column_(col), start_addr_(start_addr), - end_addr_(end_addr), - first(file_), - second(line_), - column(col) + end_addr_(end_addr) { } - const char* file_; // Maybe this should be module? + unsigned int file_index_; // Maybe this should be module? unsigned int line_; + unsigned int column_; Offset start_addr_; Offset end_addr_; + StringTablePtr strings_; +public: + StringTablePtr getStrings_() const; - public: - // DEPRECATED. First and second need to die, and column should become an accessor. - // Duplication of data is both bad and stupid, okay? - const char *first; - unsigned int second; - unsigned int column; + void setStrings_(StringTablePtr strings_); - Statement() : first(NULL), second(0) {} +public: + + Statement() : file_index_(0), line_(0), column_(0), start_addr_(0), end_addr_(0) {} struct StatementLess { bool operator () ( const Statement &lhs, const Statement &rhs ) const; }; @@ -90,27 +90,43 @@ class SYMTAB_EXPORT Statement// : public AnnotatableSparse, public Serializable typedef StatementLess LineNoTupleLess; bool operator==(const Statement &cmp) const; - bool operator==(const char* file) const {return strcmp(file, first) == 0; } - bool operator==(Offset addr) const {return startAddr() <= addr && addr < endAddr(); } +// bool operator==(const char* file) const {return strcmp(file, first) == 0; } + bool operator==(Offset addr) const { + if(startAddr() == endAddr()) { + return addr == startAddr(); + } + return (startAddr() <= addr) && (addr < endAddr()); + } ~Statement() {} Offset startAddr() const { return start_addr_;} Offset endAddr() const {return end_addr_;} - std::string getFile() const { return file_;} + std::string getFile() const; + unsigned int getFileIndex() const { return file_index_; } unsigned int getLine()const {return line_;} - unsigned int getColumn() const{return column;} + unsigned int getColumn() const { return column_; } AddressRange addressRange( ) const { return AddressRange(*this); } bool contains(Offset addr) const { return addressRange().contains(addr); } - // Does dyninst really need these? - void setLine(unsigned int l) {line_ = l;} - void setColumn(unsigned int l) {column = l;} - void setFile(const char * l) {file_ = l; first = file_;} - void setStartAddr(Offset l) {start_addr_ = l;} - void setEndAddr(Offset l) {end_addr_ = l;} typedef boost::shared_ptr Ptr; typedef boost::shared_ptr ConstPtr; + }; +template +OS& operator<<(OS& os, const Statement& s) +{ + os << ": [" << s.startAddr() << ", " << s.endAddr() << ") @ " << s.getFile() + << " (" << s.getFileIndex() << "): " << s.getLine(); + return os; +} +template +OS& operator<<(OS& os, Statement* s) +{ + os << ": [" << s->startAddr() << ", " << s->endAddr() << ") @ " << s->getFile() + << " (" << s->getFileIndex() << "): " << s->getLine(); + return os; +} + typedef Statement LineNoTuple; #define MODULE_ANNOTATABLE_CLASS AnnotatableSparse @@ -190,11 +206,11 @@ typedef Statement LineNoTuple; /***** Line Number Information *****/ bool getAddressRanges(std::vector&ranges, std::string lineSource, unsigned int LineNo); - bool getSourceLines(std::vector &lines, + bool getSourceLines(std::vector &lines, Offset addressInRange); bool getSourceLines(std::vector &lines, Offset addressInRange); - bool getStatements(std::vector &statements); + bool getStatements(std::vector &statements); LineInformation *getLineInformation(); LineInformation* parseLineInformation(); @@ -212,7 +228,7 @@ typedef Statement LineNoTuple; void addRange(Dyninst::Address low, Dyninst::Address high); void setDebugInfo(Module::DebugInfoT info); - + void finalizeRanges(); private: Dyninst::SymtabAPI::LineInformation* lineInfo_; typeCollection* typeInfo_; @@ -224,6 +240,8 @@ typedef Statement LineNoTuple; supportedLanguages language_; Offset addr_; // starting address of module Symtab *exec_; + std::vector > ranges; + bool ranges_finalized; }; template OS& operator<<(OS& os, const Module& m) @@ -252,6 +270,18 @@ struct ModRange : public interval Module* mod_; }; + template + OS& operator<<(OS& os, const ModRange& m) + { + os << m.mod() << ": [" << m.low() << ", " << m.high() << ")"; + return os; + } + template + OS& operator<<(OS& os, ModRange* m) + { + os << *m; + return os; + } }//namespace SymtabAPI diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index cc86a9836d..21358ea54b 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -90,12 +90,12 @@ namespace Dyninst { boost::multi_index::const_mem_fun > upper_bound_key; typedef typename boost::multi_index::composite_key, + boost::multi_index::const_mem_fun, boost::multi_index::const_mem_fun > line_info_key; typedef typename boost::multi_index_container < - typename Value::ConstPtr, + typename Value::Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag, addr_range_key>, boost::multi_index::ordered_non_unique< boost::multi_index::tag, upper_bound_key>, diff --git a/symtabAPI/h/StringTable.h b/symtabAPI/h/StringTable.h new file mode 100644 index 0000000000..bbfec95421 --- /dev/null +++ b/symtabAPI/h/StringTable.h @@ -0,0 +1,41 @@ +// +// Created by bill on 8/29/16. +// + +#ifndef DYNINST_STRINGTABLE_H +#define DYNINST_STRINGTABLE_H + +#include +#include +#include +#include +#include + +namespace Dyninst { + namespace SymtabAPI { + struct StringTableEntry { + std::string str; + StringTableEntry(const char* s) : str(s) {} + StringTableEntry(std::string s) : str(s) {} + bool operator==(std::string s) const { + return s == str || + s == str.substr(str.rfind("/")); + } + }; + typedef boost::multi_index_container, + boost::multi_index::ordered_non_unique< + boost::multi_index::member + > + > + > StringTable; + + typedef boost::shared_ptr StringTablePtr; + + } +} + + + +#endif //DYNINST_STRINGTABLE_H diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index ed75df3d33..4a229bcf16 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -255,7 +255,7 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, /***** Line Number Information *****/ bool getAddressRanges(std::vector &ranges, std::string lineSource, unsigned int LineNo); - bool getSourceLines(std::vector &lines, + bool getSourceLines(std::vector &lines, Offset addressInRange); bool getSourceLines(std::vector &lines, Offset addressInRange); diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 467bba62e3..ac99d07f13 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -45,29 +45,33 @@ using std::vector; #include "LineInformation.h" -LineInformation::LineInformation() : wasted_compares(0), num_queries(0) +LineInformation::LineInformation() : wasted_compares(0), num_queries(0), strings_(new StringTable) { } /* end LineInformation constructor */ -bool LineInformation::addItem_impl(Statement s) -{ - insert(Statement::ConstPtr(new Statement(s))); -// insert(s); - return true; -} -bool LineInformation::addLine( const char * lineSource, +bool LineInformation::addLine( unsigned int lineSource, unsigned int lineNo, unsigned int lineOffset, Offset lowInclusiveAddr, Offset highExclusiveAddr ) { + Statement* the_stmt = new Statement(lineSource, lineNo, lineOffset, + lowInclusiveAddr, highExclusiveAddr); + Statement::Ptr insert_me(the_stmt); + insert_me->setStrings_(strings_); + return insert( insert_me).second; - - bool ret = addItem_impl( Statement(lineSource, lineNo, lineOffset, - lowInclusiveAddr, highExclusiveAddr)); - - return ret; } /* end setLineToAddressRangeMapping() */ +bool LineInformation::addLine( std::string lineSource, + unsigned int lineNo, + unsigned int lineOffset, + Offset lowInclusiveAddr, + Offset highExclusiveAddr ) +{ + auto index = strings_->get<1>().insert(lineSource).first; + + return addLine(index->str, lineNo, lineOffset, lowInclusiveAddr, highExclusiveAddr); +} void LineInformation::addLineInfo(LineInformation *lineInfo) { @@ -89,7 +93,8 @@ bool LineInformation::addAddressRange( Offset lowInclusiveAddr, std::string print(const Dyninst::SymtabAPI::Statement& stmt) { std::stringstream stream; - stream << "Statement: < [" << stmt.startAddr() << ", " << stmt.endAddr() << "): " << stmt.getFile() << ":" << stmt.getLine() << " >"; + stream << std::hex << "Statement: < [" << stmt.startAddr() << ", " << stmt.endAddr() << "): " + << std::dec << stmt.getFile() << ":" << stmt.getLine() << " >"; return stream.str(); } @@ -98,17 +103,16 @@ bool LineInformation::getSourceLines(Offset addressInRange, vector &lines) { ++num_queries; - const_iterator start_addr_valid = project(get().upper_bound(addressInRange )); + const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); const_iterator end_addr_valid = impl_t::upper_bound(addressInRange + 1); while(start_addr_valid != end_addr_valid) { - if((*start_addr_valid)->contains(addressInRange)) + if(*(*start_addr_valid) == addressInRange) { lines.push_back(*start_addr_valid); } else { - std::cout << print(**start_addr_valid) << " does not contain " << addressInRange << std::endl; ++wasted_compares; } ++start_addr_valid; @@ -185,17 +189,29 @@ LineInformation::const_line_info_iterator LineInformation::end_by_source() const std::pair LineInformation::equal_range(std::string file, const unsigned int lineNo) const { - return get().equal_range(std::make_tuple(file, lineNo)); + auto found = strings_->get<1>().find(file); + unsigned index = strings_->project<0>(found) - strings_->begin(); + return get().equal_range(std::make_tuple(index, lineNo)); } std::pair LineInformation::equal_range(std::string file) const { - return get().equal_range(file); + auto found = strings_->get<1>().find(file); + unsigned index = strings_->project<0>(found) - strings_->begin(); + return get().equal_range(index); // const traits::line_info_index& by_line_info = impl_t::get(); // return by_line_info.equal_range(file); } +StringTablePtr LineInformation::getStrings() { + return strings_; +} + +void LineInformation::setStrings(StringTablePtr strings_) { + LineInformation::strings_ = strings_; +} + /* end LineInformation destructor */ diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 9ab7472cfa..60013f06b2 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -56,6 +56,25 @@ using namespace std; static SymtabError serr; +StringTablePtr Statement::getStrings_() const { + return strings_; +} + +void Statement::setStrings_(StringTablePtr strings) { + Statement::strings_ = strings; +} +std::string Statement::getFile() const { + if(strings_) { + if(file_index_ < strings_->size()) { + // can't be ->[] on shared pointer to multi_index container or compiler gets confused + return (*strings_)[file_index_].str; + + } + + } + return ""; +} + bool Module::findSymbol(std::vector &found, const std::string& name, @@ -136,7 +155,7 @@ bool Module::getAddressRanges(std::vector&ranges, return false; } -bool Module::getSourceLines(std::vector &lines, Offset addressInRange) +bool Module::getSourceLines(std::vector &lines, Offset addressInRange) { unsigned int originalSize = lines.size(); @@ -167,18 +186,27 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan } LineInformation *Module::parseLineInformation() { - // if non-null, we're fine + // Allocate if none if (!lineInfo_) { lineInfo_ = new LineInformation; } -// cout << "Parsing line info for module:" << *this << " with " << info_.size() << " CU entries set" << endl; - for(auto cu = info_.begin(); - cu != info_.end(); - ++cu) - { - exec()->getObject()->parseLineInfoForCU(*cu, lineInfo_); + // Parse any CUs that have been added to our list + if(!info_.empty()) { + for(auto cu = info_.begin(); + cu != info_.end(); + ++cu) + { + exec()->getObject()->parseLineInfoForCU(*cu, lineInfo_); + } + // Add ranges corresponding to each statement + std::transform(lineInfo_->begin(), lineInfo_->end(), + std::back_inserter(ranges), std::bind(&Statement::addressRange, std::placeholders::_1)); + + // Update in symtab: this module covers all ranges in its line info + finalizeRanges(); } + // Clear list of work to do info_.clear(); return lineInfo_; } @@ -289,7 +317,8 @@ Module::Module(supportedLanguages lang, Offset adr, fullName_(fullNm), language_(lang), addr_(adr), - exec_(img) + exec_(img), + ranges_finalized(false) { fileName_ = extract_pathname_tail(fullNm); } @@ -301,7 +330,8 @@ Module::Module() : fullName_(""), language_(lang_Unknown), addr_(0), - exec_(NULL) + exec_(NULL), + ranges_finalized(false) { } @@ -314,7 +344,9 @@ Module::Module(const Module &mod) : language_(mod.language_), addr_(mod.addr_), exec_(mod.exec_), - info_(mod.info_) + info_(mod.info_), + ranges_finalized(mod.ranges_finalized) + { } @@ -420,10 +452,35 @@ bool Module::findVariablesByName(std::vector &ret, const std::string void Module::addRange(Dyninst::Address low, Dyninst::Address high) { - exec_->mod_lookup()->insert(new ModRange(low, high, this)); + printf("Adding range [%lx, %lx) to %s\n", low, high, fileName().c_str()); + ranges.push_back(std::make_pair(low, high)); +// exec_->mod_lookup()->insert(new ModRange(low, high, this)); +} + +void Module::finalizeRanges() +{ + if(ranges.empty()) { + return; + } + std::sort(ranges.begin(), ranges.end()); + auto bit = ranges.begin(); + ModRange * ext = NULL; + Address ext_s = bit->first; + Address ext_e = ext_s; + + for( ; bit != ranges.end(); ++bit) { + if(bit->first > ext_e) { + ext = new ModRange(ext_s,ext_e, this); + exec_->mod_lookup()->insert(ext); + ext_s = bit->first; + } + ext_e = bit->second; + } + ext = new ModRange(ext_s, ext_e, this); + exec_->mod_lookup()->insert(ext); + ranges.clear(); } void Module::setDebugInfo(Module::DebugInfoT info) { -// cout << "Adding DIE to module:" << *this << endl; info_.push_back(info); } diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index b2b565ccfe..4da8d4c49b 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2430,10 +2430,86 @@ bool Object::fix_global_symbol_modules_static_dwarf() if (!dbg_ptr) return false; Dwarf_Debug dbg = *dbg_ptr; - ModuleFixer m(dbg, this); - bool result = m.parse(); - freeList.push_back(m.getFreeList()); - return result; + Dwarf_Arange* ranges; + Dwarf_Signed num_ranges; + status = dwarf_get_aranges(dbg, &ranges, &num_ranges, NULL); + if(status != DW_DLV_OK) return false; + std::set dies_seen; + Dwarf_Off cu_die_off; + Dwarf_Die cu_die; + for(int i = 0; i < num_ranges; i++) + { + Dwarf_Addr start; + Dwarf_Unsigned len, segment, segment_size; + // TODO: info_b has segment info from DWARF4 + status = dwarf_get_arange_info_b(ranges[i], &segment, &segment_size, &start, &len, &cu_die_off, NULL); + assert(status == DW_DLV_OK); + if(segment_size > 0) + { + cout << "WARNING: ignoring segment info" << endl; + } + if(dies_seen.find(cu_die_off) != dies_seen.end()) continue; + if(len == 0) continue; + status = dwarf_offdie_b(dbg, cu_die_off, Dwarf_Bool(true), &cu_die, NULL); + assert(status == DW_DLV_OK); + std::string modname; + if(!DwarfWalker::findDieName(dbg, cu_die, modname)) + { + modname = associated_symtab->file(); // default module + } + Offset actual_start, actual_end; + convertDebugOffset(start, actual_start); + convertDebugOffset(start + len, actual_end); + Module* m = associated_symtab->getOrCreateModule(modname, actual_start); + m->addRange(actual_start, actual_end); + cout << hex << "Set range from dw_aranges: " << modname << ": [" << actual_start << ", " << actual_end << ")" << endl; + m->setDebugInfo(cu_die); + dies_seen.insert(cu_die_off); + dwarf_dealloc(dbg, ranges[i], DW_DLA_ARANGE); + } + /* Iterate over the compilation-unit headers. */ + while (dwarf_next_cu_header_c(dbg, Dwarf_Bool(true), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &cu_die_off, NULL) == DW_DLV_OK ) + { + status = dwarf_siblingof_b(dbg, NULL, Dwarf_Bool(true), &cu_die, NULL); + assert(status == DW_DLV_OK); + if(dies_seen.find(cu_die_off) != dies_seen.end()) continue; + std::string modname; + if(!DwarfWalker::findDieName(dbg, cu_die, modname)) + { + modname = associated_symtab->file(); // default module + } + Address tempModLow; + Address modLow = 0; + if (DwarfWalker::findConstant(DW_AT_low_pc, tempModLow, cu_die, dbg)) { + convertDebugOffset(tempModLow, modLow); + } + std::vector mod_ranges = DwarfWalker::getDieRanges(dbg, cu_die, modLow); + Module* m = associated_symtab->getOrCreateModule(modname, modLow); + for(auto r = mod_ranges.begin(); + r != mod_ranges.end(); + ++r) + { + m->addRange(r->first, r->second); + } + m->setDebugInfo(cu_die); + dies_seen.insert(cu_die_off); + + } + dwarf_dealloc(dbg, ranges, DW_DLA_LIST); + +// ModuleFixer m(dbg, this); +// bool result = m.parse(); +// freeList.push_back(m.getFreeList()); +// return result; } @@ -2767,8 +2843,8 @@ stab_entry *Object::get_stab_info() const } Object::Object(MappedFile *mf_, bool, void (*err_func)(const char *), - bool alloc_syms) : - AObject(mf_, err_func), + bool alloc_syms, Symtab* st) : + AObject(mf_, err_func, st), elfHdr(NULL), hasReldyn_(false), hasReladyn_(false), @@ -3950,9 +4026,7 @@ bool AObject::getSegments(vector &segs) const } -bool Object::emitDriver(Symtab *obj, string fName, - std::vector&allSymbols, - unsigned /*flag*/) +bool Object::emitDriver(string fName, std::vector &allSymbols, unsigned) { #ifdef BINEDIT_DEBUG printf("emitting...\n"); @@ -3963,14 +4037,14 @@ bool Object::emitDriver(Symtab *obj, string fName, if (elfHdr->e_ident()[EI_CLASS] == ELFCLASS32) { Dyninst::SymtabAPI::emitElf *em = - new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, obj); + new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, associated_symtab); if( !em->createSymbolTables(allSymbols) ) return false; return em->driver(fName); } else if (elfHdr->e_ident()[EI_CLASS] == ELFCLASS64) { Dyninst::SymtabAPI::emitElf *em = - new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, obj); + new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, associated_symtab); if( !em->createSymbolTables(allSymbols) ) return false; return em->driver(fName); } @@ -3984,7 +4058,7 @@ const char *Object::interpreter_name() const /* Parse everything in the file on disk, and cache that we've done so, because our modules may not bear any relation to the name source files. */ -void Object::parseStabFileLineInfo(Symtab *st) +void Object::parseStabFileLineInfo() { static dyn_hash_map< string, bool > haveParsedFileMap; @@ -4033,7 +4107,9 @@ void Object::parseStabFileLineInfo(Symtab *st) Module* mod; moduleName = currentSourceFile; - if(!st->findModuleByName(mod, moduleName)) mod = st->getDefaultModule(); + if(!associated_symtab->findModuleByName(mod, moduleName)) { + mod = associated_symtab->getDefaultModule(); + } li_for_module = mod->getLineInformation(); if(!li_for_module) { @@ -4114,7 +4190,7 @@ void Object::parseStabFileLineInfo(Symtab *st) }; } - if (! st->findFunctionsByName(funcs, std::string(stringbuf)) + if (! associated_symtab->findFunctionsByName(funcs, std::string(stringbuf)) || !funcs.size()) { continue; @@ -4212,8 +4288,35 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) { return; } + assert( status == DW_DLV_OK ); + + StringTablePtr strings(li_for_module->getStrings()); + char** files; + size_t offset = strings->size(); + Dwarf_Signed filecount; + status = dwarf_srcfiles(cuDIE, &files, &filecount, &ignored); assert( status == DW_DLV_OK ); + // dwarf_line_srcfileno == 0 means unknown; 1...n means files[0...n-1] + // so we ensure that we're adding a block of unknown, 1...n to the string table + // and that offset + dwarf_line_srcfileno points to the correct string + strings->push_back(""); + for(int i = 0; i < filecount; i++) + { + char* tmp = NULL; + if(truncateLineFilenames && (tmp = strrchr(files[i], '/'))) + { + strings->push_back(tmp); + } + else + { + strings->push_back(files[i]); + } + dwarf_dealloc(dbg, files[i], DW_DLA_STRING); + } + dwarf_dealloc(dbg, files, DW_DLA_LIST); + li_for_module->setStrings(strings); + /* The 'lines' returned are actually interval markers; the code generated from lineNo runs from lineAddr up to but not including the lineAddr of the next line. */ @@ -4221,17 +4324,23 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) Dwarf_Unsigned previousLineNo = 0; Dwarf_Signed previousLineColumn = 0; Dwarf_Addr previousLineAddr = 0x0; - char * previousLineSource = NULL; + Dwarf_Unsigned previousLineSource = 0; Offset baseAddr = getBaseAddress(); + Dwarf_Addr cu_high_pc = 0; + dwarf_highpc(cuDIE, &cu_high_pc, NULL); + bool needs_followup = false; /* Iterate over this CU's source lines. */ for ( int i = 0; i < lineCount; i++ ) { /* Acquire the line number, address, source, and end of sequence flag. */ Dwarf_Unsigned lineNo; status = dwarf_lineno( lineBuffer[i], & lineNo, NULL ); - if ( status != DW_DLV_OK ) { continue; } + if ( status != DW_DLV_OK ) { + if(needs_followup) cout << "dwarf_lineno failed" << endl; + continue; + } Dwarf_Signed lineOff; status = dwarf_lineoff( lineBuffer[i], & lineOff, NULL ); @@ -4241,6 +4350,7 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) status = dwarf_lineaddr( lineBuffer[i], & lineAddr, NULL ); if ( status != DW_DLV_OK ) { + if(needs_followup) cout << "dwarf_lineaddr failed" << endl; continue; } @@ -4254,26 +4364,30 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) if (result) lineAddr = new_lineAddr; } - if(!isText(lineAddr)) - { - continue; - } +// if(!associated_symtab->isCode(lineAddr)) +// { +// cout << hex << "WARNING: Discarding line info for non-text addr " << hex << lineAddr << endl; +// continue; +// } - char * lineSource; - status = dwarf_linesrc( lineBuffer[i], & lineSource, NULL ); - if ( status != DW_DLV_OK ) { continue; } + Dwarf_Unsigned lineSource; + status = dwarf_line_srcfileno( lineBuffer[i], & lineSource, NULL ); + if ( status != DW_DLV_OK ) { + continue; + } Dwarf_Bool isEndOfSequence; status = dwarf_lineendsequence( lineBuffer[i], & isEndOfSequence, NULL ); - if ( status != DW_DLV_OK ) { continue; } - + if ( status != DW_DLV_OK ) { + continue; + } if ( isPreviousValid ) { /* If we're talking about the same (source file, line number) tuple, and it isn't the end of the sequence, we can coalesce the range. (The end of sequence marker marks discontinuities in the ranges.) */ - if ( lineNo == previousLineNo && strcmp( lineSource, previousLineSource ) == 0 + if ( (lineNo == previousLineNo) && (lineSource == previousLineSource) && ! isEndOfSequence ) { /* Don't update the prev* values; just keep going until we hit the end of @@ -4281,27 +4395,13 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) continue; } /* end if we can coalesce this range */ - char *canonicalLineSource; - if (truncateLineFilenames) { - canonicalLineSource = strrchr( previousLineSource, '/' ); - if( canonicalLineSource == NULL ) { canonicalLineSource = previousLineSource; } - else { ++canonicalLineSource; } - } - else { - canonicalLineSource = previousLineSource; - } - - - - Dyninst::Offset startAddrToUse = previousLineAddr; Dyninst::Offset endAddrToUse = lineAddr; - - if (startAddrToUse && endAddrToUse) + if (startAddrToUse && endAddrToUse && (startAddrToUse != endAddrToUse)) { -// cout << "\tAdding line from " << canonicalLineSource << " to " << std::hex << li_for_module <addLine(canonicalLineSource, + // string table entry. + li_for_module->addLine((unsigned int)(previousLineSource + offset), (unsigned int) previousLineNo, (unsigned int) previousLineColumn, startAddrToUse, @@ -4312,9 +4412,11 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) } /* end if the previous* variables are valid */ /* If the current line ends the sequence, invalidate previous; otherwise, update. */ + // We've seen a pattern where there are multiple lines for a given address and + // only one has an end marker. Carry through in that case. if ( isEndOfSequence ) { - isPreviousValid = false; + isPreviousValid = (lineAddr == previousLineAddr) ; } else { previousLineNo = lineNo; @@ -4332,13 +4434,13 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) -void Object::parseLineInfoForAddr(Symtab* obj, Offset addr_to_find) +void Object::parseLineInfoForAddr(Offset addr_to_find) { Dwarf_Debug *dbg_ptr = dwarf->line_dbg(); if (!dbg_ptr) return; std::set mod_for_offset; - obj->findModuleByOffset(mod_for_offset, addr_to_find); + associated_symtab->findModuleByOffset(mod_for_offset, addr_to_find); for(auto mod = mod_for_offset.begin(); mod != mod_for_offset.end(); ++mod) @@ -4352,10 +4454,10 @@ void Object::parseLineInfoForAddr(Symtab* obj, Offset addr_to_find) // Dwarf Debug Format parsing -void Object::parseDwarfFileLineInfo(Symtab* st) +void Object::parseDwarfFileLineInfo() { vector mods; - st->getAllModules(mods); + associated_symtab->getAllModules(mods); for(auto mod = mods.begin(); mod != mods.end(); ++mod) @@ -4364,27 +4466,27 @@ void Object::parseDwarfFileLineInfo(Symtab* st) } } /* end parseDwarfFileLineInfo() */ -void Object::parseFileLineInfo(Symtab *st) +void Object::parseFileLineInfo() { if(parsedAllLineInfo) return; - parseStabFileLineInfo(st); - parseDwarfFileLineInfo(st); + parseStabFileLineInfo(); + parseDwarfFileLineInfo(); parsedAllLineInfo = true; } -void Object::parseTypeInfo(Symtab *obj) +void Object::parseTypeInfo() { #if defined(TIMED_PARSE) struct timeval starttime; gettimeofday(&starttime, NULL); #endif - parseStabTypes(obj); + parseStabTypes(); Dwarf_Debug* typeInfo = dwarf->type_dbg(); if(!typeInfo) return; - DwarfWalker walker(obj, *typeInfo); + DwarfWalker walker(associated_symtab, *typeInfo); walker.parse(); freeList.push_back(walker.getFreeList()); // freeList = walker.getFreeList(); @@ -4400,9 +4502,9 @@ void Object::parseTypeInfo(Symtab *obj) #endif } -void Object::parseStabTypes(Symtab *obj) +void Object::parseStabTypes() { - types_printf("Entry to parseStabTypes for %s\n", obj->name().c_str()); + types_printf("Entry to parseStabTypes for %s\n", associated_symtab->name().c_str()); stab_entry *stabptr = NULL; const char *next_stabstr = NULL; @@ -4489,7 +4591,7 @@ void Object::parseStabTypes(Symtab *obj) ptr++; modName = ptr; } - if (obj->findModuleByName(mod, modName)) { + if (associated_symtab->findModuleByName(mod, modName)) { tc = typeCollection::getModTypeCollection(mod); parseActive = true; if (!mod) { @@ -4504,7 +4606,7 @@ void Object::parseStabTypes(Symtab *obj) } else { //parseActive = false; - mod = obj->getDefaultModule(); + mod = associated_symtab->getDefaultModule(); tc = typeCollection::getModTypeCollection(mod); types_printf("\t Warning: failed to find module name matching %s, using %s\n", modName, mod->fileName().c_str()); } @@ -4552,16 +4654,16 @@ void Object::parseStabTypes(Symtab *obj) currentFunctionName = new string(tmp); // Shouldn't this be a function name lookup? std::vectorsyms; - if(!obj->findSymbol(syms, + if(!associated_symtab->findSymbol(syms, *currentFunctionName, Symbol::ST_FUNCTION, mangledName)) { - if(!obj->findSymbol(syms, + if(!associated_symtab->findSymbol(syms, "_"+*currentFunctionName, Symbol::ST_FUNCTION, mangledName)) { string fortranName = *currentFunctionName + string("_"); - if (obj->findSymbol(syms, + if (associated_symtab->findSymbol(syms, fortranName, Symbol::ST_FUNCTION, mangledName)) { @@ -4591,11 +4693,11 @@ void Object::parseStabTypes(Symtab *obj) //TODO? change this. findLocalVar will cause an infinite loop std::vectorvars; - if(!obj->findSymbol(vars, + if(!associated_symtab->findSymbol(vars, *commonBlockName, Symbol::ST_OBJECT, mangledName)) { - if(!obj->findSymbol(vars, + if(!associated_symtab->findSymbol(vars, *commonBlockName, Symbol::ST_OBJECT, mangledName, @@ -4623,11 +4725,11 @@ void Object::parseStabTypes(Symtab *obj) case N_ECOMM: { //copy this set of fields assert(currentFunctionName); - if(!obj->findSymbol(bpfv, + if(!associated_symtab->findSymbol(bpfv, *currentFunctionName, Symbol::ST_FUNCTION, mangledName)) { - if(!obj->findSymbol(bpfv, + if(!associated_symtab->findSymbol(bpfv, *currentFunctionName, Symbol::ST_FUNCTION, mangledName, diff --git a/symtabAPI/src/Object-elf.h b/symtabAPI/src/Object-elf.h index 35882edee5..a22e94acec 100644 --- a/symtabAPI/src/Object-elf.h +++ b/symtabAPI/src/Object-elf.h @@ -270,10 +270,10 @@ class Object; public: - Object(MappedFile *, bool, void (*)(const char *) = log_msg, bool alloc_syms = true); + Object(MappedFile *, bool, void (*)(const char *) = log_msg, bool alloc_syms = true, Symtab* st = NULL); virtual ~Object(); - bool emitDriver(Symtab *obj, std::string fName, std::vector&allSymbols, unsigned flag); + bool emitDriver(std::string fName, std::vector &allSymbols, unsigned flag); const char *elf_vaddr_to_ptr(Offset vaddr) const; bool hasStabInfo() const { return ! ( !stab_off_ || !stab_size_ || !stabstr_off_ ); } @@ -281,9 +281,9 @@ class Object; stab_entry * get_stab_info() const; std::string getFileName() const; void getModuleLanguageInfo(dyn_hash_map *mod_langs); - void parseFileLineInfo(Symtab *obj); + void parseFileLineInfo(); - void parseTypeInfo(Symtab *obj); + void parseTypeInfo(); bool needs_function_binding() const { return (plt_addr_ > 0); } bool get_func_binding_table(std::vector &fbt) const; @@ -518,16 +518,16 @@ class Object; Symbol *handle_opd_symbol(Region *opd, Symbol *sym); void handle_opd_relocations(); void parse_opd(Elf_X_Shdr *); - void parseStabFileLineInfo(Symtab *); + void parseStabFileLineInfo(); public: - void parseDwarfFileLineInfo(Symtab* obj); - void parseLineInfoForAddr(Symtab* obj, Offset addr_to_find); + void parseDwarfFileLineInfo(); + void parseLineInfoForAddr(Offset addr_to_find); private: void parseLineInfoForCU(Module::DebugInfoT cuDIE, LineInformation* li); void parseDwarfTypes(Symtab *obj); - void parseStabTypes(Symtab *obj); + void parseStabTypes(); void load_object(bool); void load_shared_object(bool); diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index e301d0eb0f..ba77052480 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -1211,7 +1211,7 @@ static bool store_line_info(Symtab* st, info_for_all_files_t *baseInfo) return true; } -void Object::parseFileLineInfo(Symtab *st) +void Object::parseFileLineInfo() { if(parsedAllLineInfo) return; @@ -1238,7 +1238,7 @@ void Object::parseFileLineInfo(Symtab *st) // __FILE__, __LINE__, src_file_name, libname); return; } - store_line_info(st, &inf); + store_line_info(associated_symtab, &inf); } @@ -2170,7 +2170,7 @@ BOOL CALLBACK add_type_info(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, void *info) return TRUE; } -void Object::parseTypeInfo(Symtab *obj) { +void Object::parseTypeInfo() { proc_mod_pair pair; BOOL result; // @@ -2178,7 +2178,7 @@ void Object::parseTypeInfo(Symtab *obj) { // pair.handle = hProc; - pair.obj = obj; + pair.obj = associated_symtab; pair.base_addr = getBaseAddress(); if (!pair.base_addr) { @@ -2197,7 +2197,7 @@ void Object::parseTypeInfo(Symtab *obj) { // Parse local variables and local type information // std::vector funcs; - obj->getAllFunctions(funcs); + associated_symtab->getAllFunctions(funcs); for (unsigned i=0; i < funcs.size(); i++) { findLocalVars(funcs[i], pair); } @@ -2218,11 +2218,10 @@ bool AObject::getSegments(vector &segs) const return true; } -bool Object::emitDriver(Symtab *obj, string fName, std::vector&allSymbols, - unsigned flag) +bool Object::emitDriver(string fName, std::vector &allSymbols, unsigned flag) { emitWin *em = new emitWin((PCHAR)GetMapAddr(), this, err_func_); - return em -> driver(obj, fName); + return em -> driver(associated_symtab, fName); } // automatically discards duplicates diff --git a/symtabAPI/src/Object-nt.h b/symtabAPI/src/Object-nt.h index 9b85045db1..41f5489e27 100644 --- a/symtabAPI/src/Object-nt.h +++ b/symtabAPI/src/Object-nt.h @@ -176,7 +176,7 @@ class Object : public AObject public: SYMTAB_EXPORT Object(MappedFile *, bool defensive, - void (*)(const char *) = log_msg, bool alloc_syms = true); + void (*)(const char *) = log_msg, bool alloc_syms = true, Symtab*); SYMTAB_EXPORT virtual ~Object( void ); SYMTAB_EXPORT std::string getFileName() const { return mf->filename(); } @@ -201,13 +201,12 @@ class Object : public AObject SYMTAB_EXPORT ObjectType objType() const; SYMTAB_EXPORT const char *interpreter_name() const { return NULL; } SYMTAB_EXPORT dyn_hash_map &getLineInfo(); - SYMTAB_EXPORT void parseTypeInfo(Symtab *obj); + SYMTAB_EXPORT void parseTypeInfo(); SYMTAB_EXPORT virtual Dyninst::Architecture getArch(); SYMTAB_EXPORT void ParseGlobalSymbol(PSYMBOL_INFO pSymInfo); SYMTAB_EXPORT const std::vector &getPossibleMains() const { return possible_mains; } SYMTAB_EXPORT void getModuleLanguageInfo(dyn_hash_map *mod_langs); - SYMTAB_EXPORT bool emitDriver(Symtab *obj, std::string fName, - std::vector&allSymbols, unsigned flag); + SYMTAB_EXPORT bool emitDriver(std::string fName, std::vector &allSymbols, unsigned flag); SYMTAB_EXPORT unsigned int getSecAlign() const {return SecAlignment;} SYMTAB_EXPORT void insertPrereqLibrary(std::string lib); virtual char *mem_image() const @@ -238,10 +237,10 @@ class Object : public AObject private: SYMTAB_EXPORT void ParseSymbolInfo( bool ); - SYMTAB_EXPORT void parseFileLineInfo(Symtab * st); - SYMTAB_EXPORT void parseLineInfoForAddr(Symtab* st, Offset) + SYMTAB_EXPORT void parseFileLineInfo(); + SYMTAB_EXPORT void parseLineInfoForAddr(Offset) { - parseFileLineInfo(st); + parseFileLineInfo(associatedSymtab); } SYMTAB_EXPORT void FindInterestingSections( bool, bool ); diff --git a/symtabAPI/src/Object.C b/symtabAPI/src/Object.C index b8a6faf7db..8db1823e86 100644 --- a/symtabAPI/src/Object.C +++ b/symtabAPI/src/Object.C @@ -391,7 +391,7 @@ SYMTAB_EXPORT AObject::~AObject() } // explicitly protected -SYMTAB_EXPORT AObject::AObject(MappedFile *mf_, void (*err_func)(const char *)) +SYMTAB_EXPORT AObject::AObject(MappedFile *mf_, void (*err_func)(const char *), Symtab* st) : mf(mf_), code_ptr_(0), code_off_(0), code_len_(0), data_ptr_(0), data_off_(0), data_len_(0), @@ -401,7 +401,8 @@ SYMTAB_EXPORT AObject::AObject(MappedFile *mf_, void (*err_func)(const char *)) is_aout_(false), is_dynamic_(false), has_error(false), is_static_binary_(false), no_of_sections_(0), no_of_symbols_(0), - deferredParse(false), parsedAllLineInfo(false), err_func_(err_func), addressWidth_nbytes(4) + deferredParse(false), parsedAllLineInfo(false), err_func_(err_func), addressWidth_nbytes(4), + associated_symtab(st) { } diff --git a/symtabAPI/src/Object.h b/symtabAPI/src/Object.h index 07e13e0600..bc4e322a0b 100644 --- a/symtabAPI/src/Object.h +++ b/symtabAPI/src/Object.h @@ -147,7 +147,7 @@ class AObject { protected: SYMTAB_EXPORT virtual ~AObject(); // explicitly protected - SYMTAB_EXPORT AObject(MappedFile *, void (*err_func)(const char *)); + SYMTAB_EXPORT AObject(MappedFile *, void (*err_func)(const char *), Symtab*); virtual void parseLineInfoForCU(Module::DebugInfoT module_debug_info, LineInformation* li) { } MappedFile *mf; @@ -198,7 +198,8 @@ class AObject { int addressWidth_nbytes; std::vector catch_addrs_; //Addresses of C++ try/catch blocks; - + Symtab* associated_symtab; + private: friend class SymbolIter; friend class Symtab; diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index 9fb739ac25..bfd75df7ae 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -725,10 +725,15 @@ bool Symtab::fixSymModules(std::vector &raw_syms) if (!obj) { return false; } - const std::vector > &mods = obj->modules_; - for (unsigned i=0; i< mods.size(); i++) { - getOrCreateModule(mods[i].first, mods[i].second); + for (unsigned int i = 0; i < _mods.size(); ++i) + { + _mods[i]->finalizeRanges(); } + +// const std::vector > &mods = obj->modules_; +// for (unsigned i=0; i< mods.size(); i++) { +// getOrCreateModule(mods[i].first, mods[i].second); +// } for (unsigned i = 0; i < raw_syms.size(); i++) { fixSymModule(raw_syms[i]); } @@ -792,39 +797,9 @@ bool Symtab::createAggregates() bool Symtab::fixSymModule(Symbol *&sym) { - ////////// - ////////// - ////////// - // - // It has been decided that all libraries shall have only one - // module named after the library. The a.out has one module - // per (reported) source file, plus DEFAULT_MODULE for everything - // else. This is enforced here, although the Object-* files might - // do it as well. - Module *mod = NULL; - //if (0 && (getObjectType() == obj_SharedLib)) { - // mod = getDefaultModule(); - //} - //else { - Object *obj = getObject(); - if (!obj) - { - assert(0); - return false; - } - std::string modName = obj->findModuleForSym(sym); - if (modName.length() == 0) { - mod = getDefaultModule(); - } - else { - mod = getOrCreateModule(modName, sym->getOffset()); - } - //} - - - if (!mod) - return false; - + Module* mod = NULL; + findModuleByOffset(mod, sym->getOffset()); + if(!mod) mod = getDefaultModule(); sym->setModule(mod); return true; } @@ -1188,6 +1163,10 @@ Module *Symtab::getOrCreateModule(const std::string &modName, Module *fm = NULL; if (findModuleByName(fm, nameToUse)) { + if(modAddr && (modAddr < fm->addr())) + { + fm->addr_ = modAddr; + } return fm; } @@ -1305,7 +1284,7 @@ Symtab::Symtab(std::string filename, bool defensive_bin, bool &err) : } obj_private = new Object(mf, defensive_bin, - symtab_log_perror, true); + symtab_log_perror, true, this); if (obj_private->hasError()) { err = true; return; @@ -1374,7 +1353,7 @@ Symtab::Symtab(unsigned char *mem_image, size_t image_size, } obj_private = new Object(mf, defensive_bin, - symtab_log_perror, true); + symtab_log_perror, true, this); if (obj_private->hasError()) { err = true; return; @@ -2304,7 +2283,7 @@ void Symtab::parseLineInformation() { return; } - linkedFile->parseFileLineInfo(this); + linkedFile->parseFileLineInfo(); } SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector &ranges, @@ -2329,7 +2308,7 @@ SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector &ranges, return false; } -SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) +SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) { unsigned int originalSize = lines.size(); @@ -2366,7 +2345,7 @@ SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &line SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) { - std::vector tmp; + std::vector tmp; getSourceLines(tmp, addressInRange); if(tmp.empty()) return false; for(auto i = tmp.begin(); i != tmp.end(); ++i) @@ -2442,11 +2421,12 @@ void Symtab::parseTypes() { return; } - linkedFile->parseTypeInfo(this); + linkedFile->parseTypeInfo(); for (unsigned int i = 0; i < _mods.size(); ++i) { _mods[i]->setModuleTypes(typeCollection::getModTypeCollection(_mods[i])); + _mods[i]->finalizeRanges(); } // optionally we might want to clear the static data struct in typeCollection @@ -2625,7 +2605,7 @@ SYMTAB_EXPORT bool Symtab::emitSymbols(Object *linkedFile,std::string filename, allSyms.insert(allSyms.end(), undefDynSyms.begin(), undefDynSyms.end()); // Write the new file - return linkedFile->emitDriver(this, filename, allSyms, flag); + return linkedFile->emitDriver(filename, allSyms, flag); } SYMTAB_EXPORT bool Symtab::emit(std::string filename, unsigned flag) diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 309da5329f..a5b64c8bc1 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -194,7 +194,7 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { /* Extract the name of this module. */ std::string moduleName; - if (!findDieName( moduleDIE, moduleName )) return false; + if (!findDieName(dbg(), moduleDIE, moduleName)) return false; if (moduleName.empty() && moduleTag == DW_TAG_type_unit) { uint64_t sig8 = * reinterpret_cast(&signature); @@ -242,10 +242,6 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { if (!buildSrcFiles(moduleDIE)) return false; if(mod()) { mod()->setDebugInfo(moduleDIE); - if(modLow && modHigh) - { - mod()->addRange(modLow, modHigh); - } } @@ -559,7 +555,7 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { dwarf_printf("(0x%lx) parseSubprogram entry\n", id()); - parseRangeTypes(); + parseRangeTypes(nullptr, entry()); setFunctionFromRange(func_type); // Name first @@ -667,25 +663,22 @@ void DwarfWalker::setFuncRanges() { last_high = high; curFunc()->ranges.push_back(FuncRange(low, high - low, curFunc())); - if(mod()) mod()->addRange(low, high); } } } -bool DwarfWalker::parseHighPCLowPC(Dwarf_Die entry) +pair DwarfWalker::parseHighPCLowPC(Dwarf_Debug dbg, Dwarf_Die entry) { Dwarf_Attribute hasLow; Dwarf_Attribute hasHigh; - if(dwarf_attr(entry, DW_AT_low_pc, &hasLow, NULL) != DW_DLV_OK) return false; - if(dwarf_attr(entry, DW_AT_high_pc, &hasHigh, NULL) != DW_DLV_OK) return false; + std::pair result = make_pair(AddressRange(0,0), false); + if(dwarf_attr(entry, DW_AT_low_pc, &hasLow, NULL) != DW_DLV_OK) return result; + if(dwarf_attr(entry, DW_AT_high_pc, &hasHigh, NULL) != DW_DLV_OK) return result; Address low, high; - Address tempLow, tempHigh; - if (!findConstant(DW_AT_low_pc, tempLow, entry, dbg())) return false; - if (!findConstant(DW_AT_high_pc, tempHigh, entry, dbg())) return false; - low = convertDebugOffset(tempLow); - high = convertDebugOffset(tempHigh); + if (!findConstant(DW_AT_low_pc, low, entry, dbg)) return result; + if (!findConstant(DW_AT_high_pc, high, entry, dbg)) return result; Dwarf_Half form; DWARF_FAIL_RET(dwarf_whatform(hasHigh, &form, NULL)); @@ -693,69 +686,78 @@ bool DwarfWalker::parseHighPCLowPC(Dwarf_Die entry) { high += low; } - dwarf_printf("(0x%lx) Lexical block from 0x%lx to 0x%lx\n", id(), low, high); - setRange(make_pair(low, high)); - if(mod()) mod()->addRange(low, high); - return true; - + dwarf_printf("Lexical block from 0x%lx to 0x%lx\n", low, high); + result = make_pair(AddressRange(low, high), true); + return result; } - -bool DwarfWalker::parseRangeTypes() { +bool DwarfWalker::parseRangeTypes(Dwarf_Debug dbg, Dwarf_Die die) { dwarf_printf("(0x%lx) Parsing ranges\n", id()); clearRanges(); - parseHighPCLowPC(entry()); + std::vector newRanges = getDieRanges(dbg, die, modLow); + for(auto r = newRanges.begin(); + r != newRanges.end(); + ++r) + { + setRange(*r); + } + return !newRanges.empty(); +} +vector DwarfWalker::getDieRanges(Dwarf_Debug dbg, Dwarf_Die die, Offset range_base) { + std::vector newRanges; + auto highlow = parseHighPCLowPC(dbg, die); + if(highlow.second) newRanges.push_back(highlow.first); - Dwarf_Bool hasRanges = false; - DWARF_FAIL_RET(dwarf_hasattr(entry(), DW_AT_ranges, &hasRanges, NULL)); - if (hasRanges) { + Dwarf_Bool hasRanges = false; + int status = (dwarf_hasattr(die, DW_AT_ranges, &hasRanges, NULL)); + if ((status == DW_DLV_OK) && hasRanges) { Address range_offset; - if (!findConstant(DW_AT_ranges, range_offset, entry(), dbg())) return false; - - Dwarf_Ranges *ranges = NULL; - Dwarf_Signed ranges_length = 0; - DWARF_FAIL_RET(dwarf_get_ranges_a(dbg(), (Dwarf_Off) range_offset, entry(), - &ranges, &ranges_length, NULL, NULL)); - - bool done = false; - for (unsigned i = 0; i < ranges_length && !done; i++) { - Dwarf_Ranges *cur = ranges + i; - Address cur_base = modLow; - switch (cur->dwr_type) { - case DW_RANGES_ENTRY: { - Address low = cur->dwr_addr1 + cur_base; - Address high = cur->dwr_addr2 + cur_base; - dwarf_printf("(0x%lx) Lexical block from 0x%lx to 0x%lx\n", id(), low, high); - setRange(make_pair(low, high)); - mod()->addRange(low, high); - break; - } - case DW_RANGES_ADDRESS_SELECTION: - cur_base = cur->dwr_addr2; - break; - case DW_RANGES_END: - done = true; - break; - } + if (findConstant(DW_AT_ranges, range_offset, die, dbg)) + { + Dwarf_Ranges *ranges = NULL; + Dwarf_Signed ranges_length = 0; + status = (dwarf_get_ranges_a(dbg, (Dwarf_Off) range_offset, die, + &ranges, &ranges_length, NULL, NULL)); + bool done = (status != DW_DLV_OK); + for (unsigned i = 0; i < ranges_length && !done; i++) { + Dwarf_Ranges cur = ranges[i]; + Address cur_base = range_base; + switch (cur.dwr_type) { + case DW_RANGES_ENTRY: { + Address low = cur.dwr_addr1 + cur_base; + Address high = cur.dwr_addr2 + cur_base; + dwarf_printf("Lexical block from 0x%lx to 0x%lx\n", low, high); + newRanges.push_back(AddressRange(low, high)); + // mod()->addRange(low, high); + break; + } + case DW_RANGES_ADDRESS_SELECTION: + cur_base = cur.dwr_addr2; + break; + case DW_RANGES_END: + done = true; + break; + } + } + dwarf_ranges_dealloc(dbg, ranges, ranges_length); } - dwarf_ranges_dealloc(dbg(), ranges, ranges_length); } - return true; + return newRanges; } bool DwarfWalker::parseLexicalBlock() { dwarf_printf("(0x%lx) Parsing lexical block\n", id()); - return parseRangeTypes(); + return parseRangeTypes(nullptr, entry()); } bool DwarfWalker::parseCommonBlock() { dwarf_printf("(0x%lx) Parsing common block\n", id()); std::string commonBlockName; - if (!findDieName( entry(), commonBlockName )) return false; + if (!findDieName(dbg(), entry(), commonBlockName)) return false; Symbol* commonBlockVar = findSymbolForCommonBlock(commonBlockName); if(!commonBlockVar) { @@ -1395,7 +1397,7 @@ bool DwarfWalker::handleSpecification(bool &hasSpec) { return true; } -bool DwarfWalker::findDieName(Dwarf_Die die, std::string &name) { +bool DwarfWalker::findDieName(Dwarf_Debug dbg, Dwarf_Die die, std::string &name) { char *cname = NULL; Dwarf_Error error; @@ -1406,7 +1408,7 @@ bool DwarfWalker::findDieName(Dwarf_Die die, std::string &name) { if (dwarf_errno(error) == DW_DLE_ATTR_FORM_BAD) { status = DW_DLV_NO_ENTRY; } - dwarf_dealloc( dbg(), error, DW_DLA_ERROR ); + dwarf_dealloc( dbg, error, DW_DLA_ERROR ); } DWARF_CHECK_RET(status == DW_DLV_ERROR); @@ -1416,12 +1418,12 @@ bool DwarfWalker::findDieName(Dwarf_Die die, std::string &name) { } name = cname; - dwarf_dealloc( dbg(), cname, DW_DLA_STRING ); + dwarf_dealloc( dbg, cname, DW_DLA_STRING ); return true; } bool DwarfWalker::findName(std::string &name) { - if (!findDieName( specEntry(), name)) return false; + if (!findDieName(dbg(), specEntry(), name)) return false; dwarf_printf("(0x%lx) Found name %s\n", id(), name.c_str()); return true; } @@ -1447,7 +1449,7 @@ bool DwarfWalker::findFuncName() { return true; } - findDieName( entry(), curName() ); + findDieName(dbg(), entry(), curName()); setMangledName(false); return true; } @@ -2201,7 +2203,7 @@ bool DwarfWalker::decipherBound(Dwarf_Attribute boundAttribute, Dwarf_Bool is_in DWARF_FAIL_RET(dwarf_offdie_b( dbg(), boundOffset, is_info, & boundEntry, NULL )); /* Does it have a name? */ - if (findDieName( boundEntry, boundString ) + if (findDieName(dbg(), boundEntry, boundString) && !boundString.empty()) return true; @@ -2540,3 +2542,4 @@ void DwarfWalker::setFuncReturnType() { curFunc()->setReturnType(returnType); } } + diff --git a/symtabAPI/src/dwarfWalker.h b/symtabAPI/src/dwarfWalker.h index 71afe8def1..fc06116269 100644 --- a/symtabAPI/src/dwarfWalker.h +++ b/symtabAPI/src/dwarfWalker.h @@ -1,7 +1,10 @@ +#include + #if !defined(_dwarf_walker_h_) #define _dwarf_walker_h_ + #include "elf.h" #include "libelf.h" #include "libdwarf.h" @@ -186,6 +189,8 @@ namespace Dyninst { // A Context must be provided as an _input_ to this function, // whereas parse creates a context. bool parse_int(Dwarf_Die entry, bool parseSiblings); + static std::pair::iterator, std::vector::iterator> + parseRangeList(Dwarf_Ranges *ranges, Dwarf_Signed num_ranges, Offset initial_base); private: enum inline_t { NormalFunc, @@ -194,7 +199,7 @@ namespace Dyninst { bool parseSubprogram(inline_t func_type); bool parseLexicalBlock(); - bool parseRangeTypes(); + bool parseRangeTypes(Dwarf_Debug dbg, Dwarf_Die die); bool parseCommonBlock(); bool parseConstant(); virtual bool parseVariable(); @@ -210,7 +215,7 @@ namespace Dyninst { bool parseMember(); bool parseConstPackedVolatile(); bool parseTypeReferences(); - bool parseHighPCLowPC(Dwarf_Die entry); + static std::pair parseHighPCLowPC(Dwarf_Debug dbg, Dwarf_Die entry); // These vary as we parse the tree @@ -258,7 +263,9 @@ namespace Dyninst { bool getLineInformation(Dwarf_Unsigned &variableLineNo, bool &hasLineNumber, std::string &filename); - bool findDieName(Dwarf_Die die, std::string &); + public: + static bool findDieName(Dwarf_Debug dbg, Dwarf_Die die, std::string &); + private: bool findName(std::string &); void removeFortranUnderscore(std::string &); bool findSize(unsigned &size); @@ -284,6 +291,7 @@ namespace Dyninst { static bool findConstantWithForm(Dwarf_Attribute &attr, Dwarf_Half form, Address &value); + static std::vector getDieRanges(Dwarf_Debug dbg, Dwarf_Die die, Offset base); private: bool decodeConstantLocation(Dwarf_Attribute &attr, Dwarf_Half form, std::vector &locs); From 13643e7ab4e6dc8f2408363692ce86f9974610e9 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 6 Sep 2016 10:54:13 -0500 Subject: [PATCH 123/180] Assorted cleanup. Fixed infinite loop in IBSTree_fast::find. --- common/h/IBSTree-fast.h | 261 ++++++++++++++++---------------- parseAPI/h/CFG.h | 20 ++- parseAPI/h/CFGFactory.h | 3 +- parseAPI/src/Block.C | 15 ++ symtabAPI/h/LineInformation.h | 4 +- symtabAPI/h/Module.h | 22 ++- symtabAPI/h/RangeLookup.h | 4 + symtabAPI/src/LineInformation.C | 16 +- symtabAPI/src/Module.C | 60 ++++++-- symtabAPI/src/Object-elf.C | 2 +- symtabAPI/src/dwarfWalker.C | 20 +-- 11 files changed, 256 insertions(+), 171 deletions(-) diff --git a/common/h/IBSTree-fast.h b/common/h/IBSTree-fast.h index 6de654d378..fa3a800593 100644 --- a/common/h/IBSTree-fast.h +++ b/common/h/IBSTree-fast.h @@ -35,153 +35,156 @@ #include #include #include +#include namespace Dyninst { - template > - class IBSTree_fast - { - typedef typename ITYPE::type interval_type; + template > + class IBSTree_fast + { + typedef typename ITYPE::type interval_type; - IBSTree overlapping_intervals; - typedef boost::multi_index_container > - > > interval_set; - - //typedef std::set > interval_set; - interval_set unique_intervals; + IBSTree overlapping_intervals; + typedef boost::multi_index_container > + > > interval_set; - public: - IBSTree_fast() - { - } - ~IBSTree_fast() - { - } - int size() const - { - return overlapping_intervals.size() + unique_intervals.size(); - } - bool empty() const - { - return unique_intervals.empty() && overlapping_intervals.empty(); - } - void insert(ITYPE*); - void remove(ITYPE*); - int find(interval_type, std::set &) const; - int find(ITYPE* I, std::set&) const; - void successor(interval_type X, std::set& ) const; - ITYPE* successor(interval_type X) const; - void clear(); - - }; - - template - void IBSTree_fast::insert(ITYPE* entry) - { - // find in overlapping first - std::set dummy; - if(overlapping_intervals.find(entry, dummy)) - { - overlapping_intervals.insert(entry); - return; - } - typename interval_set::iterator lower = - unique_intervals.upper_bound(entry->low()); - // lower.high first >= entry.low - if(lower != unique_intervals.end() && *lower == entry) return; - auto upper = lower; - while(upper != unique_intervals.end() && - (*upper)->low() <= entry->high()) - { - overlapping_intervals.insert(*upper); - ++upper; - } - if(upper != lower) + //typedef std::set > interval_set; + interval_set unique_intervals; + + public: + IBSTree_fast() + { + } + ~IBSTree_fast() + { + std::cerr << "Fast interval tree had " << unique_intervals.size() << " unique intervals and " << overlapping_intervals.size() << " overlapping" << std::endl; + } + int size() const + { + return overlapping_intervals.size() + unique_intervals.size(); + } + bool empty() const + { + return unique_intervals.empty() && overlapping_intervals.empty(); + } + void insert(ITYPE*); + void remove(ITYPE*); + int find(interval_type, std::set &) const; + int find(ITYPE* I, std::set&) const; + void successor(interval_type X, std::set& ) const; + ITYPE* successor(interval_type X) const; + void clear(); + + }; + + template + void IBSTree_fast::insert(ITYPE* entry) { - unique_intervals.erase(lower, upper); - overlapping_intervals.insert(entry); + // find in overlapping first + std::set dummy; + if(overlapping_intervals.find(entry, dummy)) + { + overlapping_intervals.insert(entry); + return; + } + typename interval_set::iterator lower = + unique_intervals.upper_bound(entry->low()); + // lower.high first >= entry.low + if(lower != unique_intervals.end() && (**lower == *entry)) return; + auto upper = lower; + while(upper != unique_intervals.end() && + (*upper)->low() <= entry->high()) + { + overlapping_intervals.insert(*upper); + ++upper; + } + if(upper != lower) + { + unique_intervals.erase(lower, upper); + overlapping_intervals.insert(entry); + } + else + { + unique_intervals.insert(entry); + } } - else + template + void IBSTree_fast::remove(ITYPE* entry) { - unique_intervals.insert(entry); + overlapping_intervals.remove(entry); + auto found = unique_intervals.find(entry->high()); + if(found != unique_intervals.end() && *found == entry) unique_intervals.erase(found); } - } - template - void IBSTree_fast::remove(ITYPE* entry) - { - overlapping_intervals.remove(entry); - auto found = unique_intervals.find(entry->high()); - if(found != unique_intervals.end() && *found == entry) unique_intervals.erase(found); - } - template - int IBSTree_fast::find(interval_type X, std::set &results) const - { - int num_old_results = results.size(); - - int num_overlapping = overlapping_intervals.find(X, results); - if(num_overlapping > 0) return num_overlapping; - - typename interval_set::const_iterator found_unique = unique_intervals.upper_bound(X); - if(found_unique != unique_intervals.end()) + template + int IBSTree_fast::find(interval_type X, std::set &results) const { - if((*found_unique)->low() > X) return 0; - results.insert(*found_unique); + int num_old_results = results.size(); + + int num_overlapping = overlapping_intervals.find(X, results); + if(num_overlapping > 0) return num_overlapping; + + typename interval_set::const_iterator found_unique = unique_intervals.upper_bound(X); + if(found_unique != unique_intervals.end()) + { + if((*found_unique)->low() > X) return 0; + results.insert(*found_unique); + } + return results.size() - num_old_results; } - return results.size() - num_old_results; - } - template - int IBSTree_fast::find(ITYPE* I, std::set&results) const - { - int num_old_results = results.size(); - int num_overlapping = overlapping_intervals.find(I, results); - if(num_overlapping) return num_overlapping; - typename interval_set::const_iterator lb = unique_intervals.upper_bound(I->low()); - auto ub = lb; - while(ub != unique_intervals.end() && (*ub)->low() < I->high()) + template + int IBSTree_fast::find(ITYPE* I, std::set&results) const { - results.insert(*ub); + int num_old_results = results.size(); + int num_overlapping = overlapping_intervals.find(I, results); + if(num_overlapping) return num_overlapping; + typename interval_set::const_iterator lb = unique_intervals.upper_bound(I->low()); + auto ub = lb; + while(ub != unique_intervals.end() && (*ub)->low() < I->high()) + { + results.insert(*ub); + ++ub; + } + return results.size() - num_old_results; } - return results.size() - num_old_results; - } - template - void IBSTree_fast::successor(interval_type X, std::set& results) const - { - ITYPE* overlapping_ub = overlapping_intervals.successor(X); - - typename interval_set::const_iterator unique_ub = unique_intervals.upper_bound(X); - if(overlapping_ub && (unique_ub != unique_intervals.end())) + template + void IBSTree_fast::successor(interval_type X, std::set& results) const { - results.insert(overlapping_ub->low() < (*unique_ub)->low() ? overlapping_ub : *unique_ub); + ITYPE* overlapping_ub = overlapping_intervals.successor(X); + + typename interval_set::const_iterator unique_ub = unique_intervals.upper_bound(X); + if(overlapping_ub && (unique_ub != unique_intervals.end())) + { + results.insert(overlapping_ub->low() < (*unique_ub)->low() ? overlapping_ub : *unique_ub); + } + else if(overlapping_ub) + { + results.insert(overlapping_ub); + } + else if(unique_ub != unique_intervals.end()) + { + results.insert(*unique_ub); + } } - else if(overlapping_ub) + template + ITYPE* IBSTree_fast::successor(interval_type X) const { - results.insert(overlapping_ub); + std::set tmp; + successor(X, tmp); + assert(tmp.size() <= 1); + if(tmp.empty()) return NULL; + return *tmp.begin(); + } - else if(unique_ub != unique_intervals.end()) + template + void IBSTree_fast::clear() { - results.insert(*unique_ub); + overlapping_intervals.clear(); + unique_intervals.clear(); } - } - template - ITYPE* IBSTree_fast::successor(interval_type X) const - { - std::set tmp; - successor(X, tmp); - assert(tmp.size() <= 1); - if(tmp.empty()) return NULL; - return *tmp.begin(); - - } - template - void IBSTree_fast::clear() - { - overlapping_intervals.clear(); - unique_intervals.clear(); - } - - + + } #endif diff --git a/parseAPI/h/CFG.h b/parseAPI/h/CFG.h index de655244d8..7d37e47445 100644 --- a/parseAPI/h/CFG.h +++ b/parseAPI/h/CFG.h @@ -342,8 +342,12 @@ class PARSER_EXPORT Block : public Dyninst::interval
, }; static void destroy(Block *b); - - private: + + bool operator==(const Block &rhs) const; + + bool operator!=(const Block &rhs) const; + +private: void addSource(Edge * e); void addTarget(Edge * e); void removeTarget(Edge * e); @@ -674,7 +678,17 @@ class PARSER_EXPORT FuncExtent : public Dyninst::interval
{ /* interval implementation */ Address low() const { return _start; } - Address high() const { return _end; } + Address high() const { return _end; } + + bool operator==(const FuncExtent &rhs) const { + return _func == rhs._func && + _start == rhs._start && + _end == rhs._end; + } + + bool operator!=(const FuncExtent &rhs) const { + return !(rhs == *this); + } }; /** Natural loops diff --git a/parseAPI/h/CFGFactory.h b/parseAPI/h/CFGFactory.h index eee90ce250..d9d31a34b3 100644 --- a/parseAPI/h/CFGFactory.h +++ b/parseAPI/h/CFGFactory.h @@ -159,7 +159,8 @@ class PARSER_EXPORT CFGFactory { }; -} + + } } #endif diff --git a/parseAPI/src/Block.C b/parseAPI/src/Block.C index 136f7f847b..bf82dd7c45 100644 --- a/parseAPI/src/Block.C +++ b/parseAPI/src/Block.C @@ -252,3 +252,18 @@ Block::getInsn(Offset a) const { } +bool Block::operator==(const Block &rhs) const { + return _obj == rhs._obj && + _region == rhs._region && + _start == rhs._start && + _end == rhs._end && + _lastInsn == rhs._lastInsn && + _srclist == rhs._srclist && + _trglist == rhs._trglist && + _func_cnt == rhs._func_cnt && + _parsed == rhs._parsed; +} + +bool Block::operator!=(const Block &rhs) const { + return !(rhs == *this); +} diff --git a/symtabAPI/h/LineInformation.h b/symtabAPI/h/LineInformation.h index 0a05dd4b4d..14e7dcefff 100644 --- a/symtabAPI/h/LineInformation.h +++ b/symtabAPI/h/LineInformation.h @@ -105,8 +105,8 @@ class SYMTAB_EXPORT LineInformation : void setStrings(StringTablePtr strings_); protected: - int wasted_compares; - int num_queries; + mutable int wasted_compares; + mutable int num_queries; }; diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 6a6864d1ca..d9f6f9aa61 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -240,9 +240,11 @@ typedef Statement LineNoTuple; supportedLanguages language_; Offset addr_; // starting address of module Symtab *exec_; - std::vector > ranges; + std::set ranges; bool ranges_finalized; -}; + + void finalizeOneRange(Address ext_s, Address ext_e) const; + }; template OS& operator<<(OS& os, const Module& m) { @@ -262,6 +264,22 @@ struct ModRange : public interval ModRange(Offset l, Offset h, Module* m) : low_(l), high_(h), mod_(m) {} + + bool operator==(const ModRange &rhs) const { + return low_ == rhs.low_ && + high_ == rhs.high_ && + mod_ == rhs.mod_; + } + + bool operator!=(const ModRange &rhs) const { + return !(rhs == *this); + } + bool contains(const ModRange& rhs) const { + return (rhs.low() >= low()) && + (rhs.high() <= high()) && + (rhs.mod() == mod() ); + } + Offset low() const { return low_; } Offset high() const { return high_; } Module* mod() const { return mod_;} diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index 21358ea54b..592a7b75db 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -66,6 +66,10 @@ namespace Dyninst { first = start; second = end; } + AddressRange merge(const AddressRange& other) + { + return AddressRange(std::min(first, other.first), std::max(second, other.second)); + } bool operator==(const AddressRange& rhs) const { return (first == rhs.first) && (second == rhs.second); } diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index ac99d07f13..a30a81185a 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -156,7 +156,10 @@ LineInformation::const_iterator LineInformation::end() const LineInformation::const_iterator LineInformation::find(Offset addressInRange) const { - return impl_t::find(addressInRange); + ++num_queries; + const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); + if(start_addr_valid == end()) return end(); + return (*start_addr_valid)->contains(addressInRange) ? start_addr_valid : end(); } /* end find() */ @@ -170,11 +173,12 @@ unsigned LineInformation::getSize() const LineInformation::~LineInformation() { - if(num_queries) - { - std::cout << "Line information with " << getSize() << " entries queried " << num_queries << " times with " - << wasted_compares << " extra compares (" << (float)(wasted_compares) / (num_queries) << " per query)" << std::endl; - } +// std::cerr << "Line information with " << getSize() << " entries queried " << num_queries << " times"; +// if(num_queries) +// { +// std::cerr << " with " << wasted_compares << " extra compares (" << (float)(wasted_compares) / (num_queries) << " per query)"; +// } +// std::cerr << std::endl; } LineInformation::const_line_info_iterator LineInformation::begin_by_source() const { diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 60013f06b2..d98366c0f6 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -187,6 +187,9 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan LineInformation *Module::parseLineInformation() { // Allocate if none + using std::placeholders::_1; + using std::bind; + using std::for_each; if (!lineInfo_) { lineInfo_ = new LineInformation; @@ -200,8 +203,8 @@ LineInformation *Module::parseLineInformation() { exec()->getObject()->parseLineInfoForCU(*cu, lineInfo_); } // Add ranges corresponding to each statement - std::transform(lineInfo_->begin(), lineInfo_->end(), - std::back_inserter(ranges), std::bind(&Statement::addressRange, std::placeholders::_1)); + for_each(lineInfo_->begin(), lineInfo_->end(), + bind(&Module::addRange, this, bind(&Statement::startAddr, _1), bind(&Statement::endAddr, _1))); // Update in symtab: this module covers all ranges in its line info finalizeRanges(); @@ -452,8 +455,24 @@ bool Module::findVariablesByName(std::vector &ret, const std::string void Module::addRange(Dyninst::Address low, Dyninst::Address high) { - printf("Adding range [%lx, %lx) to %s\n", low, high, fileName().c_str()); - ranges.push_back(std::make_pair(low, high)); +// printf("Adding range [%lx, %lx) to %s\n", low, high, fileName().c_str()); + std::set::iterator lb = ranges.lower_bound(AddressRange(low, high)); + if(lb != ranges.end() && lb->first <= low) + { + if(lb->second >= high) + { + return; + } + ranges.insert(AddressRange(lb->first, high)); +// printf("Actual is [%lx, %lx) due to overlap with [%lx, %lx)\n", lb->first, high, lb->first, lb->second); + ranges.erase(lb); + } + else + { + ranges.insert(AddressRange(low, high)); + } + +// ranges.push_back(std::make_pair(low, high)); // exec_->mod_lookup()->insert(new ModRange(low, high, this)); } @@ -462,25 +481,46 @@ void Module::finalizeRanges() if(ranges.empty()) { return; } - std::sort(ranges.begin(), ranges.end()); auto bit = ranges.begin(); - ModRange * ext = NULL; Address ext_s = bit->first; Address ext_e = ext_s; for( ; bit != ranges.end(); ++bit) { if(bit->first > ext_e) { - ext = new ModRange(ext_s,ext_e, this); - exec_->mod_lookup()->insert(ext); + finalizeOneRange(ext_s, ext_e); ext_s = bit->first; } ext_e = bit->second; } - ext = new ModRange(ext_s, ext_e, this); - exec_->mod_lookup()->insert(ext); + finalizeOneRange(ext_s, ext_e); ranges.clear(); } +void Module::finalizeOneRange(Address ext_s, Address ext_e) const { + ModRange* r = new ModRange(ext_s, ext_e, const_cast(this)); + ModRangeLookup* lookup = exec_->mod_lookup(); + std::set existing; + lookup->find(r, existing); +// cerr << "Found " << existing.size() << " overlapping intervals at insert time" << endl; + for(auto i = existing.begin(); + i != existing.end(); + ++i) + { + if((*i) && (*i)->contains(*r)) + { +// cerr << "Skipping duplicate ModRange " << r << endl; + delete r; + return; + } + if(r->contains(**i)) + { +// cerr << "Removing duplicate ModRange " << (*i) << endl; + lookup->remove(*i); + } + } + exec_->mod_lookup()->insert(r); +} + void Module::setDebugInfo(Module::DebugInfoT info) { info_.push_back(info); } diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 4da8d4c49b..95cb9aa1d2 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2462,7 +2462,7 @@ bool Object::fix_global_symbol_modules_static_dwarf() convertDebugOffset(start + len, actual_end); Module* m = associated_symtab->getOrCreateModule(modname, actual_start); m->addRange(actual_start, actual_end); - cout << hex << "Set range from dw_aranges: " << modname << ": [" << actual_start << ", " << actual_end << ")" << endl; +// cout << hex << "Set range from dw_aranges: " << modname << ": [" << actual_start << ", " << actual_end << ")" << endl; m->setDebugInfo(cu_die); dies_seen.insert(cu_die_off); dwarf_dealloc(dbg, ranges[i], DW_DLA_ARANGE); diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index a5b64c8bc1..995e4a8dc7 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -225,14 +225,8 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { if (findConstant(DW_AT_high_pc, tempModHigh, entry(), dbg())) { modHigh = convertDebugOffset(tempModHigh); } - // We have enough info to make a new module if we have a low address. - if(modLow && symtab()) - { - mod() = symtab()->getOrCreateModule(moduleName, modLow); - } else - { - setModuleFromName(moduleName); - } + + setModuleFromName(moduleName); //dwarf_printf("Mapped to Symtab module %s\n", mod()->fileName().c_str()); @@ -240,9 +234,6 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { fixUnknownMod = mod(); if (!buildSrcFiles(moduleDIE)) return false; - if(mod()) { - mod()->setDebugInfo(moduleDIE); - } if (!parse_int(moduleDIE, true)) return false; @@ -436,12 +427,7 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { DWARF_CHECK_RET(status == DW_DLV_ERROR); /* Deallocate the entry we just parsed. */ - if(tag() != DW_TAG_compile_unit && - tag() != DW_TAG_partial_unit && - tag() != DW_TAG_type_unit) - { dwarf_dealloc( dbg(), entry(), DW_DLA_DIE ); - } if (status != DW_DLV_OK) { break; @@ -555,7 +541,7 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { dwarf_printf("(0x%lx) parseSubprogram entry\n", id()); - parseRangeTypes(nullptr, entry()); + parseRangeTypes(dbg(), entry()); setFunctionFromRange(func_type); // Name first From 018929b3e8a35cedd514aae272846a77e1225648 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 7 Sep 2016 13:25:12 -0500 Subject: [PATCH 124/180] Added interface for line info find-with-hint. Fixed dwarfWalker bug where we doubled up on compensating for one-based indexing. dwarfWalker now uses/fills a Module's stringtable directly. StringTables now streamable for debugging. Inlines use string table entries for filenames. --- common/src/debug_common.h | 2 +- symtabAPI/h/Function.h | 3 +- symtabAPI/h/LineInformation.h | 10 +-- symtabAPI/h/Module.h | 14 ++++- symtabAPI/h/StringTable.h | 18 ++++++ symtabAPI/src/Function.C | 18 ++++-- symtabAPI/src/LineInformation.C | 10 +++ symtabAPI/src/Module.C | 16 ++++- symtabAPI/src/Object-elf.C | 2 - symtabAPI/src/dwarfWalker.C | 107 +++++++++++++++++++------------- symtabAPI/src/dwarfWalker.h | 19 +++--- 11 files changed, 143 insertions(+), 76 deletions(-) diff --git a/common/src/debug_common.h b/common/src/debug_common.h index ad87771ecc..12ca408838 100644 --- a/common/src/debug_common.h +++ b/common/src/debug_common.h @@ -34,7 +34,7 @@ #include #include "util.h" -extern int common_debug_dwarf; +COMMON_EXPORT extern int common_debug_dwarf; extern int common_debug_addrtranslate; #if defined(__GNUC__) diff --git a/symtabAPI/h/Function.h b/symtabAPI/h/Function.h index 77180021b5..a088e5f4ea 100644 --- a/symtabAPI/h/Function.h +++ b/symtabAPI/h/Function.h @@ -198,8 +198,9 @@ class SYMTAB_EXPORT InlinedFunction : public FunctionBase virtual std::string getName() const; virtual Offset getOffset() const; virtual unsigned getSize() const; + void setFile(std::string filename); private: - const char* callsite_file; + int callsite_file_number; Dyninst::Offset callsite_line; std::string name_; Module* module_; diff --git a/symtabAPI/h/LineInformation.h b/symtabAPI/h/LineInformation.h index 14e7dcefff..9f421502f0 100644 --- a/symtabAPI/h/LineInformation.h +++ b/symtabAPI/h/LineInformation.h @@ -86,19 +86,13 @@ class SYMTAB_EXPORT LineInformation : const_iterator begin() const; const_iterator end() const; const_iterator find(Offset addressInRange) const; + const_iterator find(Offset addressInRange, const_iterator hint) const; unsigned getSize() const; virtual ~LineInformation(); - + StringTablePtr strings_; protected: - /* We maintain internal copies of all the source file names. Because - both directions of the mapping include pointers to these names, - maintain a separate list of them, and only ever deallocate those - (in the destructor). Note that it speeds and simplifies things - to have the string pointers be the same. */ - - StringTablePtr strings_; public: StringTablePtr getStrings() ; diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index d9f6f9aa61..22e7b11b64 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -96,6 +96,12 @@ class SYMTAB_EXPORT Statement return addr == startAddr(); } return (startAddr() <= addr) && (addr < endAddr()); + } + bool operator<(Offset addr) const { + return startAddr() <= addr; + } + bool operator>(Offset addr) const { + return !((*this) < addr || (*this == addr)); } ~Statement() {} @@ -229,7 +235,7 @@ typedef Statement LineNoTuple; void setDebugInfo(Module::DebugInfoT info); void finalizeRanges(); - private: + private: Dyninst::SymtabAPI::LineInformation* lineInfo_; typeCollection* typeInfo_; std::vector info_; @@ -241,6 +247,12 @@ typedef Statement LineNoTuple; Offset addr_; // starting address of module Symtab *exec_; std::set ranges; + + StringTablePtr strings_; + public: + StringTablePtr & getStrings() ; + + private: bool ranges_finalized; void finalizeOneRange(Address ext_s, Address ext_e) const; diff --git a/symtabAPI/h/StringTable.h b/symtabAPI/h/StringTable.h index bbfec95421..21348b7b27 100644 --- a/symtabAPI/h/StringTable.h +++ b/symtabAPI/h/StringTable.h @@ -32,6 +32,24 @@ namespace Dyninst { > StringTable; typedef boost::shared_ptr StringTablePtr; + template + os& operator<<(os& s, StringTableEntry e) + { + s << e.str; + return s; + } + + template + os& operator<<(os& stream, const StringTable& tbl) + { + for(int i = 0; i < tbl.size(); ++i) + { + stream << tbl[i] << " @ " << i << std::endl; + } + return stream; + } + + } } diff --git a/symtabAPI/src/Function.C b/symtabAPI/src/Function.C index df08cb3ee1..9942c729b2 100644 --- a/symtabAPI/src/Function.C +++ b/symtabAPI/src/Function.C @@ -209,10 +209,11 @@ bool FunctionBase::setFramePtr(vector *locs) std::pair InlinedFunction::getCallsite() { - if(callsite_file) { - return make_pair(callsite_file, callsite_line); + std::string callsite_file = ""; + if(callsite_file_number > 0 && callsite_file_number < module_->getStrings()->size()) { + callsite_file = (*module_->getStrings())[callsite_file_number].str; } - return make_pair("", callsite_line); + return make_pair(callsite_file, callsite_line); } void FunctionBase::expandLocation(const VariableLocation &loc, @@ -431,7 +432,7 @@ bool FunctionBase::operator==(const FunctionBase &f) InlinedFunction::InlinedFunction(FunctionBase *parent) : FunctionBase(), - callsite_file(NULL), + callsite_file_number(0), callsite_line(0), module_(parent->getModule()) { @@ -476,6 +477,15 @@ unsigned InlinedFunction::getSize() const return functionSize_;//inline_parent->getSize(); } +void InlinedFunction::setFile(string filename) { + StringTablePtr strs = module_->getStrings(); + // This looks gross, but here's what it does: + // Get index 1 (unique by name). Insert the filename on that index (which defaults to push_back if empty). + // Returns an ; get the iterator (we don't care if it's new). Project to random access (index 0). + // Difference from begin == array index in string table. + callsite_file_number = strs->project<0>(strs->get<1>().insert(filename).first) - strs->begin(); +} + Module* Function::getModule() const { return module_; } \ No newline at end of file diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index a30a81185a..6d9ada9ca2 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -217,5 +217,15 @@ void LineInformation::setStrings(StringTablePtr strings_) { LineInformation::strings_ = strings_; } +LineInformation::const_iterator LineInformation::find(Offset addressInRange, const_iterator hint) const { + while(hint != end()) + { + if((**hint) == addressInRange) return hint; + if((**hint) > addressInRange) break; + ++hint; + } + return find(addressInRange); +} + /* end LineInformation destructor */ diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index d98366c0f6..41a6ba6405 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -193,6 +193,8 @@ LineInformation *Module::parseLineInformation() { if (!lineInfo_) { lineInfo_ = new LineInformation; + // share our string table + lineInfo_->setStrings(strings_); } // Parse any CUs that have been added to our list if(!info_.empty()) { @@ -321,7 +323,8 @@ Module::Module(supportedLanguages lang, Offset adr, language_(lang), addr_(adr), exec_(img), - ranges_finalized(false) + ranges_finalized(false), + strings_(new StringTable) { fileName_ = extract_pathname_tail(fullNm); } @@ -334,7 +337,8 @@ Module::Module() : language_(lang_Unknown), addr_(0), exec_(NULL), - ranges_finalized(false) + ranges_finalized(false), + strings_(new StringTable) { } @@ -348,7 +352,8 @@ Module::Module(const Module &mod) : addr_(mod.addr_), exec_(mod.exec_), info_(mod.info_), - ranges_finalized(mod.ranges_finalized) + ranges_finalized(mod.ranges_finalized), + strings_(mod.strings_) { } @@ -524,3 +529,8 @@ void Module::finalizeOneRange(Address ext_s, Address ext_e) const { void Module::setDebugInfo(Module::DebugInfoT info) { info_.push_back(info); } + +StringTablePtr & Module::getStrings() { + return strings_; +} + diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 95cb9aa1d2..df96f33a53 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4488,8 +4488,6 @@ void Object::parseTypeInfo() if(!typeInfo) return; DwarfWalker walker(associated_symtab, *typeInfo); walker.parse(); - freeList.push_back(walker.getFreeList()); -// freeList = walker.getFreeList(); #if defined(TIMED_PARSE) struct timeval endtime; gettimeofday(&endtime, NULL); diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index 995e4a8dc7..d83a7cf274 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -94,13 +94,6 @@ DwarfWalker::DwarfWalker(Symtab *symtab, Dwarf_Debug dbg) } DwarfWalker::~DwarfWalker() { - freeList.clear(); -} - -DwarfWalker::FreeListT DwarfWalker::getFreeList() -{ - // return by copy, so ownership gets shared - return freeList; } @@ -258,14 +251,17 @@ void DwarfParseActions::setModuleFromName(std::string moduleName) bool DwarfWalker::buildSrcFiles(Dwarf_Die entry) { Dwarf_Signed cnt = 0; - DWARF_ERROR_RET(dwarf_srcfiles(entry, &srcFileList_, &cnt, NULL)); - srcFiles_.clear(); - srcFiles_.push_back(""); + char** srcFileList; + DWARF_ERROR_RET(dwarf_srcfiles(entry, &srcFileList, &cnt, NULL)); + + if(!srcFiles()->empty()) return true; // already parsed, the module had better be right. + srcFiles()->push_back("Unknown file"); for (unsigned i = 0; i < cnt; ++i) { - srcFiles_.push_back(srcFileList_[i]); - freeList.push_back(boost::shared_ptr(const_cast(srcFiles_[i]), boost::bind(dwarf_dealloc, dbg(), _1, DW_DLA_STRING))); + srcFiles()->push_back(srcFileList[i]); + dwarf_dealloc(dbg(), srcFileList[i], DW_DLA_STRING); } - freeList.push_back(boost::shared_ptr(srcFileList_, boost::bind(dwarf_dealloc, dbg(), _1, DW_DLA_LIST))); +// cout << "Module " << mod()->fileName() << " srcfiles: " << endl << *srcFiles() << endl; + dwarf_dealloc(dbg(), srcFileList, DW_DLA_LIST); return true; } @@ -317,8 +313,8 @@ bool DwarfWalker::parse_int(Dwarf_Die e, bool p) { switch(tag()) { case DW_TAG_subprogram: case DW_TAG_entry_point: - ret = parseSubprogram(NormalFunc); - break; + ret = parseSubprogram(NormalFunc); + break; case DW_TAG_inlined_subroutine: ret = parseSubprogram(InlinedFunc); break; @@ -450,7 +446,7 @@ bool DwarfWalker::parseCallsite() if (!has_line) return true; - const char* inline_file; + std::string inline_file; bool result = findString(DW_AT_call_file, inline_file); if (!result) return false; @@ -461,7 +457,10 @@ bool DwarfWalker::parseCallsite() return false; InlinedFunction *ifunc = static_cast(curFunc()); - ifunc->callsite_file = inline_file; +// cout << "Found inline call site in func (0x" << hex << id() << ") " +// << curFunc()->getName() << " at " << curFunc()->getOffset() << dec +// << ", file " << inline_file << ": " << inline_line << endl; + ifunc->setFile(inline_file); ifunc->callsite_line = inline_line; return true; } @@ -493,8 +492,7 @@ bool DwarfWalker::setFunctionFromRange(inline_t func_type) } if (func_type == InlinedFunc) { - createInlineFunc(); - if(!curFunc()) return false; + return createInlineFunc(); } //Try to associate the function with existing symbols @@ -516,14 +514,17 @@ void DwarfWalker::setFuncFromLowest(Address lowest) { } } -void DwarfWalker::createInlineFunc() { +bool DwarfWalker::createInlineFunc() { FunctionBase *parent = curFunc(); if (parent) { InlinedFunction *ifunc = new InlinedFunction(parent); setFunc(ifunc); +// cout << "Created new inline, parent is " << parent->getName() << endl; + return true; } else { //InlinedSubroutine without containing subprogram. Weird. dwarf_printf("(0x%lx) setFunctionFromRange found inline without parent, returning false\n", id()); + return false; } } @@ -536,18 +537,24 @@ void DwarfParseActions::addPrettyFuncName(std::string name) curFunc()->addPrettyName(name, true, true); } +void restore(int old) { + common_debug_dwarf = old; +} bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { bool name_result; - + int old = common_debug_dwarf; + boost::shared_ptr guard(static_cast(0), bind(restore, old)); +// common_debug_dwarf = 1; dwarf_printf("(0x%lx) parseSubprogram entry\n", id()); parseRangeTypes(dbg(), entry()); setFunctionFromRange(func_type); // Name first + FunctionBase *func = curFunc(); name_result = findFuncName(); - - if (curEnclosure() && !curFunc()) { +// if(func) cout << hex << "Begin parseSubprogram for (" << id() << ") " << func->getName() << " at " << func->getOffset() << dec << endl; + if (curEnclosure() && !func) { // This is a member function; create the type entry // Since curFunc is false, we're not going back to reparse this // entry with a function object. @@ -565,13 +572,13 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { // parsing a specification or abstract entry at the top-level //This keeps us from parsing abstracts or specifications until // we need them. - if (!curFunc()) { + if (!func) { dwarf_printf("(0x%lx) parseSubprogram not parsing children b/c curFunc() NULL\n", id()); setParseChild(false); return true; } - if (parsedFuncs.find(curFunc()) != parsedFuncs.end()) { + if (parsedFuncs.find(func) != parsedFuncs.end()) { dwarf_printf("(0x%lx) parseSubprogram not parsing children b/c curFunc() not in parsedFuncs\n", id()); if(name_result) { dwarf_printf("\tname is %s\n", curName().c_str()); @@ -583,17 +590,19 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { if (name_result && !curName().empty()) { dwarf_printf("(0x%lx) Identified function name as %s\n", id(), curName().c_str()); if (isMangledName()) { - addMangledFuncName(curName()); + func->addMangledName(curName(), true); } // Only keep pretty names around for inlines, which probably don't have mangled names else { - dwarf_printf("(0x%lx) Adding as pretty name to inline\n", id()); - addPrettyFuncName(curName()); +// printf("(0x%lx) Adding %s as pretty name to inline at 0x%lx\n", id(), curName().c_str(), func->getOffset()); + dwarf_printf("(0x%lx) Adding as pretty name to inline\n", id()); + func->addPrettyName(curName(), true); } } //Collect callsite information for inlined functions. if (func_type == InlinedFunc) { +// cout << "Parsing callsite for (0x" << hex << id() << ") " << curName() << " at " << func->getOffset() << dec << endl; parseCallsite(); } @@ -602,7 +611,7 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { // Get range information if (hasRanges()) { - setFuncRanges(); + setRanges(func); } // Dwarf outlines some function information. You have the base entry, which contains // address ranges, frame base information, and optionally a "abstract origin" @@ -631,15 +640,18 @@ bool DwarfWalker::parseSubprogram(DwarfWalker::inline_t func_type) { if (!parse_int(specEntry(), false)) return false; } - parsedFuncs.insert(curFunc()); + parsedFuncs.insert(func); + if (func_type == InlinedFunc) { +// cout << "End parseSubprogram for inlined func " << curName() << " at " << func->getOffset() << endl; + } return true; } -void DwarfWalker::setFuncRanges() { - if(curFunc()->ranges.empty()) { +void DwarfWalker::setRanges(FunctionBase *func) { + if(func->ranges.empty()) { Address last_low = 0, last_high = 0; - curFunc()->ranges.reserve(rangesSize()); + func->ranges.reserve(rangesSize()); for (auto i = ranges_begin(); i != ranges_end(); i++) { Address low = i->first; Address high = i->second; @@ -648,7 +660,7 @@ void DwarfWalker::setFuncRanges() { last_low = low; last_high = high; - curFunc()->ranges.push_back(FuncRange(low, high - low, curFunc())); + func->ranges.push_back(FuncRange(low, high - low, curFunc())); } } } @@ -704,6 +716,7 @@ vector DwarfWalker::getDieRanges(Dwarf_Debug dbg, Dwarf_Die die, O { Dwarf_Ranges *ranges = NULL; Dwarf_Signed ranges_length = 0; + dwarf_printf("calling ranges_a, offset 0x%lx, die %p\n", range_offset, die); status = (dwarf_get_ranges_a(dbg, (Dwarf_Off) range_offset, die, &ranges, &ranges_length, NULL, NULL)); bool done = (status != DW_DLV_OK); @@ -736,7 +749,7 @@ vector DwarfWalker::getDieRanges(Dwarf_Debug dbg, Dwarf_Die die, O bool DwarfWalker::parseLexicalBlock() { dwarf_printf("(0x%lx) Parsing lexical block\n", id()); - return parseRangeTypes(nullptr, entry()); + return parseRangeTypes(dbg(), entry()); } bool DwarfWalker::parseCommonBlock() { @@ -1377,6 +1390,7 @@ bool DwarfWalker::handleSpecification(bool &hasSpec) { DWARF_FAIL_RET(dwarf_offdie_b( dbg(), specOffset, is_info, & specE, NULL )); dwarf_dealloc( dbg(), specAttribute, DW_DLA_ATTR ); +// cout << "Set spec entry" << endl; setSpecEntry(specE); @@ -1435,7 +1449,9 @@ bool DwarfWalker::findFuncName() { return true; } - findDieName(dbg(), entry(), curName()); + if(findDieName(dbg(), entry(), curName())) { +// cout << "Found DIE pretty name: " << curName() << endl; + } setMangledName(false); return true; } @@ -1618,12 +1634,12 @@ bool DwarfWalker::getLineInformation(Dwarf_Unsigned &variableLineNo, Dwarf_Unsigned fileNameDeclVal; DWARF_FAIL_RET(dwarf_formudata(fileDeclAttribute, &fileNameDeclVal, NULL)); dwarf_dealloc( dbg(), fileDeclAttribute, DW_DLA_ATTR ); - if (fileNameDeclVal >= srcFiles().size()) { + if (fileNameDeclVal > srcFiles()->size() || fileNameDeclVal <= 0) { dwarf_printf("Dwarf error reading line index %d from srcFiles of size %lu\n", - fileNameDeclVal, srcFiles().size()); + fileNameDeclVal, srcFiles()->size()); return false; } - fileName = srcFiles()[fileNameDeclVal]; + fileName = (*srcFiles())[fileNameDeclVal].str; } else { return true; @@ -1731,7 +1747,7 @@ bool DwarfWalker::checkForConstantOrExpr(Dwarf_Half attr, } bool DwarfWalker::findString(Dwarf_Half attr, - const char* &str) + string &str) { Dwarf_Half form; Dwarf_Attribute strattr; @@ -1741,12 +1757,13 @@ bool DwarfWalker::findString(Dwarf_Half attr, bool result = findConstant(attr, line_index, entry(), dbg()); if (!result) return false; - if (line_index >= srcFiles().size()) { + if (line_index >= mod()->getStrings()->size()) { dwarf_printf("Dwarf error reading line index %d from srcFiles of size %lu\n", - line_index, srcFiles().size()); + line_index, mod()->getStrings()->size()); return false; } - str = srcFiles()[line_index]; +// cout << "findString found " << (*srcFiles())[line_index].str << " at srcFiles[" << line_index << "] for " << mod()->fileName() << endl; + str = (*srcFiles())[line_index].str; return true; } @@ -1762,6 +1779,7 @@ bool DwarfWalker::findString(Dwarf_Half attr, case DW_FORM_string: { char *s = NULL; DWARF_FAIL_RET(dwarf_formstring(strattr, &s, NULL)); +// cout << "findString found " << s << " in DW_FORM_string" << endl; str = s; result = true; break; @@ -1774,7 +1792,8 @@ bool DwarfWalker::findString(Dwarf_Half attr, DWARF_FAIL_RET(dwarf_formblock(strattr, &block, NULL)); str = (char *) block->bl_data; dwarf_dealloc(dbg(), block, DW_DLA_BLOCK); - result = bool(str); +// cout << "findString found " << str << " in DW_FORM_block" << endl; + result = !str.empty(); break; } default: diff --git a/symtabAPI/src/dwarfWalker.h b/symtabAPI/src/dwarfWalker.h index fc06116269..151bebb97c 100644 --- a/symtabAPI/src/dwarfWalker.h +++ b/symtabAPI/src/dwarfWalker.h @@ -177,9 +177,7 @@ namespace Dyninst { DwarfWalker(Symtab *symtab, Dwarf_Debug dbg); virtual ~DwarfWalker(); - typedef - std::vector > FreeListT; - FreeListT getFreeList(); + bool parse(); // Takes current debug state as represented by dbg_; @@ -228,7 +226,7 @@ namespace Dyninst { bool nameDefined() { return name_ != ""; } // These are invariant across a parse - std::vector &srcFiles() { return srcFiles_; } + StringTablePtr srcFiles() { return mod()->getStrings(); } // For functions and variables with a separate specification, a // pointer to that spec. For everyone else, this points to entry @@ -285,7 +283,7 @@ namespace Dyninst { bool &constant, bool &expr, Dwarf_Half &form); - bool findString(Dwarf_Half attr, const char* &str); + bool findString(Dwarf_Half attr, std::string &str); public: static bool findConstant(Dwarf_Half attr, Address &value, Dwarf_Die entry, Dwarf_Debug dbg); static bool findConstantWithForm(Dwarf_Attribute &attr, @@ -318,9 +316,6 @@ namespace Dyninst { private: std::vector srcFiles_; char** srcFileList_; - - FreeListT freeList; - std::string name_; bool is_mangled_name_; @@ -361,14 +356,14 @@ namespace Dyninst { Dwarf_Unsigned variableLineNo, const std::string &fileName); - virtual void createInlineFunc(); + virtual bool createInlineFunc(); virtual void setFuncFromLowest(Address lowest); virtual void createParameter(const std::vector &locs, Type *paramType, Dwarf_Unsigned lineNo, const std::string &fileName); - virtual void setFuncRanges(); + virtual void setRanges(FunctionBase *func); virtual void createGlobalVariable(const std::vector &locs, Type *type); @@ -405,7 +400,7 @@ namespace Dyninst { } - virtual void createInlineFunc() {} + virtual bool createInlineFunc() {} virtual void setFuncFromLowest(Address lowest) { m_obj->setModuleForOffset(lowest, modname); @@ -418,7 +413,7 @@ namespace Dyninst { } - virtual void setFuncRanges() { + virtual void setRanges(FunctionBase *func) { } From 0e5d8340573d40a53c317b1c2532119129a517f3 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 8 Sep 2016 15:44:05 -0500 Subject: [PATCH 125/180] Cleanup so we build cleanly under boost 1.41/gcc 4.4 again. --- dataflowAPI/src/SymEvalPolicy.C | 2 +- symtabAPI/src/LineInformation.C | 14 ++++++- symtabAPI/src/Module.C | 23 +++++------ symtabAPI/src/Object-elf.C | 7 +--- symtabAPI/src/Object.h | 2 +- symtabAPI/src/dwarfWalker.h | 71 --------------------------------- 6 files changed, 27 insertions(+), 92 deletions(-) diff --git a/dataflowAPI/src/SymEvalPolicy.C b/dataflowAPI/src/SymEvalPolicy.C index c18cc9f378..674e4d4be7 100644 --- a/dataflowAPI/src/SymEvalPolicy.C +++ b/dataflowAPI/src/SymEvalPolicy.C @@ -351,7 +351,7 @@ Absloc SymEvalPolicy_64::convert(PowerpcRegisterClass regtype, int regNum) case powerpc_last_register_class:break; } assert(0); - return Absloc(); + return Absloc(); } Absloc SymEvalPolicy_64::convert(X86GeneralPurposeRegister r) diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 6d9ada9ca2..d18398ac2f 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -44,6 +44,7 @@ using namespace Dyninst::SymtabAPI; using std::vector; #include "LineInformation.h" +#include LineInformation::LineInformation() : wasted_compares(0), num_queries(0), strings_(new StringTable) { @@ -195,7 +196,18 @@ std::pairget<1>().find(file); unsigned index = strings_->project<0>(found) - strings_->begin(); - return get().equal_range(std::make_tuple(index, lineNo)); +// auto search_info = std::make_tuple(index, lineNo); + std::pair bounds; + bounds = get().equal_range(index); + while((*bounds.first)->getLine() < lineNo && bounds.first != bounds.second) { + ++bounds.first; + } + while((*bounds.second)->getLine() > lineNo && bounds.second != bounds.first) { + --bounds.second; + } + if(bounds.second != get().end()) ++bounds.second; + return bounds; +// return get().equal_range(boost::cref >(search_info)); } diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 41a6ba6405..150d7821f1 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -45,6 +45,7 @@ #include "common/src/pathName.h" #include "common/src/serialize.h" #include "Object.h" +#include #if defined(cap_dwarf) #include "dwarfWalker.h" @@ -187,9 +188,7 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan LineInformation *Module::parseLineInformation() { // Allocate if none - using std::placeholders::_1; - using std::bind; - using std::for_each; + using boost::bind; if (!lineInfo_) { lineInfo_ = new LineInformation; @@ -205,8 +204,8 @@ LineInformation *Module::parseLineInformation() { exec()->getObject()->parseLineInfoForCU(*cu, lineInfo_); } // Add ranges corresponding to each statement - for_each(lineInfo_->begin(), lineInfo_->end(), - bind(&Module::addRange, this, bind(&Statement::startAddr, _1), bind(&Statement::endAddr, _1))); + std::for_each(lineInfo_->begin(), lineInfo_->end(), + boost::bind(&Module::addRange, this, boost::bind(&Statement::startAddr, _1), boost::bind(&Statement::endAddr, _1))); // Update in symtab: this module covers all ranges in its line info finalizeRanges(); @@ -323,8 +322,8 @@ Module::Module(supportedLanguages lang, Offset adr, language_(lang), addr_(adr), exec_(img), - ranges_finalized(false), - strings_(new StringTable) + strings_(new StringTable), + ranges_finalized(false) { fileName_ = extract_pathname_tail(fullNm); } @@ -337,8 +336,8 @@ Module::Module() : language_(lang_Unknown), addr_(0), exec_(NULL), - ranges_finalized(false), - strings_(new StringTable) + strings_(new StringTable), + ranges_finalized(false) { } @@ -350,10 +349,10 @@ Module::Module(const Module &mod) : fullName_(mod.fullName_), language_(mod.language_), addr_(mod.addr_), - exec_(mod.exec_), info_(mod.info_), - ranges_finalized(mod.ranges_finalized), - strings_(mod.strings_) + exec_(mod.exec_), + strings_(mod.strings_), + ranges_finalized(mod.ranges_finalized) { } diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index df96f33a53..f9000d9cec 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2462,7 +2462,6 @@ bool Object::fix_global_symbol_modules_static_dwarf() convertDebugOffset(start + len, actual_end); Module* m = associated_symtab->getOrCreateModule(modname, actual_start); m->addRange(actual_start, actual_end); -// cout << hex << "Set range from dw_aranges: " << modname << ": [" << actual_start << ", " << actual_end << ")" << endl; m->setDebugInfo(cu_die); dies_seen.insert(cu_die_off); dwarf_dealloc(dbg, ranges[i], DW_DLA_ARANGE); @@ -2506,11 +2505,7 @@ bool Object::fix_global_symbol_modules_static_dwarf() } dwarf_dealloc(dbg, ranges, DW_DLA_LIST); -// ModuleFixer m(dbg, this); -// bool result = m.parse(); -// freeList.push_back(m.getFreeList()); -// return result; - + return true; } #else diff --git a/symtabAPI/src/Object.h b/symtabAPI/src/Object.h index bc4e322a0b..8dacfa10e0 100644 --- a/symtabAPI/src/Object.h +++ b/symtabAPI/src/Object.h @@ -148,7 +148,7 @@ class AObject { SYMTAB_EXPORT virtual ~AObject(); // explicitly protected SYMTAB_EXPORT AObject(MappedFile *, void (*err_func)(const char *), Symtab*); - virtual void parseLineInfoForCU(Module::DebugInfoT module_debug_info, LineInformation* li) { } + virtual void parseLineInfoForCU(Module::DebugInfoT , LineInformation* ) { } MappedFile *mf; diff --git a/symtabAPI/src/dwarfWalker.h b/symtabAPI/src/dwarfWalker.h index 151bebb97c..1ae44838f6 100644 --- a/symtabAPI/src/dwarfWalker.h +++ b/symtabAPI/src/dwarfWalker.h @@ -374,77 +374,6 @@ namespace Dyninst { virtual Symbol *findSymbolForCommonBlock(const std::string &commonBlockName); }; - class ModuleFixer: public DwarfWalker { - private: - virtual bool findType(Type *& /*type*/, bool /*defaultToVoid*/) { - return false; - } - public: - virtual std::string filename() const { - return obj()->getFileName(); - } - - ModuleFixer(Dwarf_Debug dbg, Object* obj) - : DwarfWalker(NULL, dbg), m_obj(obj) {} - virtual ~ModuleFixer() {} - protected: - virtual void setFuncReturnType() { - } - virtual Object* obj() const { - return m_obj; - } - - virtual void createLocalVariable(const std::vector & /*locs*/, Type * /*type*/, - Dwarf_Unsigned /*variableLineNo*/, - const std::string & /*fileName*/) { - } - - - virtual bool createInlineFunc() {} - - virtual void setFuncFromLowest(Address lowest) { - m_obj->setModuleForOffset(lowest, modname); - //setParseChild(false); - } - - - virtual void createParameter(const std::vector & /*locs*/, Type * /*paramType*/, Dwarf_Unsigned /*lineNo*/, - const std::string & /*fileName*/) { - } - - - virtual void setRanges(FunctionBase *func) { - } - - - virtual void createGlobalVariable(const std::vector & /*locs*/, Type * /*type*/) { - } - - - virtual bool addStaticClassVariable(const std::vector &locs, Type *type) { - return false; - } - - - virtual typeCommon *getCommonBlockType(std::string & /*commonBlockName*/) { - return NULL; - } - virtual void setModuleFromName(std::string moduleName) { - modname = moduleName; - } - - - virtual Symbol *findSymbolForCommonBlock(const std::string & /*commonBlockName*/) { - return NULL; - } - virtual bool parseVariable() { - return true; - } - private: - Object *m_obj; - std::string modname; - }; - }; }; From e5fc00d5b2e9832768aec5a610911daa3fd48ea8 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 13 Sep 2016 14:24:22 -0500 Subject: [PATCH 126/180] Fix signed/unsigned warning --- symtabAPI/h/Function.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symtabAPI/h/Function.h b/symtabAPI/h/Function.h index a088e5f4ea..4300ce553b 100644 --- a/symtabAPI/h/Function.h +++ b/symtabAPI/h/Function.h @@ -200,7 +200,7 @@ class SYMTAB_EXPORT InlinedFunction : public FunctionBase virtual unsigned getSize() const; void setFile(std::string filename); private: - int callsite_file_number; + size_t callsite_file_number; Dyninst::Offset callsite_line; std::string name_; Module* module_; From 77b32176ffc6e01257affad243bc9cb194a1e571 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 13 Sep 2016 14:24:58 -0500 Subject: [PATCH 127/180] Remove dead code --- symtabAPI/h/RangeLookup.h | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index 592a7b75db..f7df9d3926 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -114,45 +114,6 @@ namespace Dyninst { }; -// template -// class SYMTAB_EXPORT RangeLookup : public RangeLookupIndexTypes::Values { -// -// public: -// typedef std::pair AddressRange; -// typedef typename RangeLookupIndexTypes::Values parent; -// RangeLookup(); -// -// /* Values are copied: a RangeLookup considers itself the primary repository. */ -// bool addValue(Value v) { -// parent::insert(v); -// return true; -// } -// -// /* Likewise, copies of the values are returned. */ -// bool getValues(Offset addressInRange, std::vector &values) { -// auto by_addr_range = parent::get<0>(); -// auto found = by_addr_range.equal_range(addressInRange); -// std::copy(found.first, found.second, std::back_inserter(values)); -// return found.first != found.second; -// } -// template -// bool getAddressRanges(const char* lineSource, int lineNo, _OI out_iter) const { -// auto &by_line_info = parent::get<1>(); -// if(lineNo <= 0) // wildcard it -// { -// auto lines = by_line_info.equal_range(lineSource); -// std::copy(lines.first, lines.second, out_iter); -// return lines.first != lines.second; -// } -// auto lines = by_line_info.equal_range(lineSource, lineNo); -// std::copy(lines.first, lines.second, out_iter); -// return lines.first != lines.second; -// -// } -// virtual ~RangeLookup(); -// -// -// }; /* end class RangeLookup */ } } From b8c1e82a95f7f3e9fcba9898bd9f140ade849108 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 13 Sep 2016 14:26:17 -0500 Subject: [PATCH 128/180] Factor out arange parsing and avoid early exit if it's absent --- symtabAPI/src/Object-elf.C | 29 ++++++++++++++++++++--------- symtabAPI/src/Object-elf.h | 1 + 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index f9000d9cec..ec945549cc 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2423,20 +2423,15 @@ void pd_dwarf_handler(Dwarf_Error error, Dwarf_Ptr /*userData*/) Dwarf_Signed declFileNo = 0; char ** declFileNoToName = NULL; -bool Object::fix_global_symbol_modules_static_dwarf() +bool Object::dwarf_parse_aranges(Dwarf_Debug dbg, std::set& dies_seen) { - /* Initialize libdwarf. */ - Dwarf_Debug *dbg_ptr = dwarf->type_dbg(); - if (!dbg_ptr) - return false; - Dwarf_Debug dbg = *dbg_ptr; Dwarf_Arange* ranges; Dwarf_Signed num_ranges; - status = dwarf_get_aranges(dbg, &ranges, &num_ranges, NULL); + int status = dwarf_get_aranges(dbg, &ranges, &num_ranges, NULL); if(status != DW_DLV_OK) return false; - std::set dies_seen; Dwarf_Off cu_die_off; Dwarf_Die cu_die; +// cout << "Processing " << num_ranges << "DWARF ranges" << endl; for(int i = 0; i < num_ranges; i++) { Dwarf_Addr start; @@ -2466,6 +2461,21 @@ bool Object::fix_global_symbol_modules_static_dwarf() dies_seen.insert(cu_die_off); dwarf_dealloc(dbg, ranges[i], DW_DLA_ARANGE); } + dwarf_dealloc(dbg, ranges, DW_DLA_LIST); + return true; +} + +bool Object::fix_global_symbol_modules_static_dwarf() +{ + /* Initialize libdwarf. */ + Dwarf_Debug *dbg_ptr = dwarf->type_dbg(); + if (!dbg_ptr) + return false; + Dwarf_Debug dbg = *dbg_ptr; + std::set dies_seen; + Dwarf_Off cu_die_off; + Dwarf_Die cu_die; + dwarf_parse_aranges(dbg, dies_seen); /* Iterate over the compilation-unit headers. */ while (dwarf_next_cu_header_c(dbg, Dwarf_Bool(true), NULL, @@ -2478,7 +2488,7 @@ bool Object::fix_global_symbol_modules_static_dwarf() NULL, &cu_die_off, NULL) == DW_DLV_OK ) { - status = dwarf_siblingof_b(dbg, NULL, Dwarf_Bool(true), &cu_die, NULL); + int status = dwarf_siblingof_b(dbg, NULL, Dwarf_Bool(true), &cu_die, NULL); assert(status == DW_DLV_OK); if(dies_seen.find(cu_die_off) != dies_seen.end()) continue; std::string modname; @@ -2486,6 +2496,7 @@ bool Object::fix_global_symbol_modules_static_dwarf() { modname = associated_symtab->file(); // default module } +// cout << "Processing CU DIE for " << modname << endl; Address tempModLow; Address modLow = 0; if (DwarfWalker::findConstant(DW_AT_low_pc, tempModLow, cu_die, dbg)) { diff --git a/symtabAPI/src/Object-elf.h b/symtabAPI/src/Object-elf.h index a22e94acec..5d27b4a3be 100644 --- a/symtabAPI/src/Object-elf.h +++ b/symtabAPI/src/Object-elf.h @@ -525,6 +525,7 @@ class Object; private: void parseLineInfoForCU(Module::DebugInfoT cuDIE, LineInformation* li); + bool dwarf_parse_aranges(Dwarf_Debug dbg, std::set& dies_seen); void parseDwarfTypes(Symtab *obj); void parseStabTypes(); From 14fa0590eb42d31f33c74ebd91ac3f7653b6324f Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 13 Sep 2016 14:27:01 -0500 Subject: [PATCH 129/180] Clean up stream operators: warnings, template vs. std::ostream --- symtabAPI/h/StringTable.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/symtabAPI/h/StringTable.h b/symtabAPI/h/StringTable.h index 21348b7b27..f0d9bebf83 100644 --- a/symtabAPI/h/StringTable.h +++ b/symtabAPI/h/StringTable.h @@ -32,17 +32,16 @@ namespace Dyninst { > StringTable; typedef boost::shared_ptr StringTablePtr; - template - os& operator<<(os& s, StringTableEntry e) + + inline std::ostream& operator<<(std::ostream& s, StringTableEntry e) { s << e.str; return s; } - template - os& operator<<(os& stream, const StringTable& tbl) + inline std::ostream& operator<<(std::ostream& stream, const StringTable& tbl) { - for(int i = 0; i < tbl.size(); ++i) + for(size_t i = 0; i < tbl.size(); ++i) { stream << tbl[i] << " @ " << i << std::endl; } From 9ddd957603d38a345fb50b2359c8ea13e1101d91 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 19 Sep 2016 16:00:51 -0500 Subject: [PATCH 130/180] Build fixup --- symtabAPI/src/Object-elf.C | 2 -- 1 file changed, 2 deletions(-) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index ec945549cc..2dbb0ac17f 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2514,8 +2514,6 @@ bool Object::fix_global_symbol_modules_static_dwarf() dies_seen.insert(cu_die_off); } - dwarf_dealloc(dbg, ranges, DW_DLA_LIST); - return true; } From 967ec2d6f4a5f6d461a8c77a6b2870f4e4f26b6f Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 19 Sep 2016 16:01:12 -0500 Subject: [PATCH 131/180] Ensure default module goes at the beginning of _mods so we can avoid lookup-by-name. --- symtabAPI/src/Symtab-lookup.C | 12 ++---------- symtabAPI/src/Symtab.C | 29 +++++------------------------ 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index e863918707..3154d45a59 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -896,16 +896,8 @@ bool Symtab::getContainingInlinedFunction(Offset offset, FunctionBase* &func) } Module *Symtab::getDefaultModule() { - Module *mod = NULL; - // TODO: automatically pick the module that contains this address? - // For now, DEFAULT_MODULE or (if we have only one) that one. - if (_mods.size() == 1) - return _mods[0]; - else { - if (!findModuleByName(mod, name())) - return NULL; - } - return mod; + if(_mods.empty()) createDefaultModule(); + return _mods[0]; } unsigned Function::getSize() const { diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index bfd75df7ae..4a688ccce1 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -1125,25 +1125,11 @@ void Symtab::setModuleLanguages(dyn_hash_map *m } void Symtab::createDefaultModule() { - Module *mod = NULL; - // if (1 || getObjectType() == obj_SharedLib) { - mod = new Module(lang_Unknown, - imageOffset_, - name(), - this); - // } - // else { - //mod = new Module(lang_Unknown, - // imageOffset_, - //#if defined(os_vxworks) - // VxWorks' kernel objects should - // have their own module. - // name(), - //#else - // "DEFAULT_MODULE", - //#endif - // this); - // } + assert(_mods.empty()); + Module *mod = new Module(lang_Unknown, + imageOffset_, + name(), + this); modsByFileName[mod->fileName()] = mod; modsByFullName[mod->fullName()] = mod; _mods.push_back(mod); @@ -1535,11 +1521,6 @@ bool Symtab::extractInfo(Object *linkedFile) return false; } - // don't sort the symbols--preserve the original ordering - //sort(raw_syms.begin(),raw_syms.end(),symbol_compare); - - createDefaultModule(); - if (!fixSymModules(raw_syms)) { serr = Syms_To_Functions; From ed78eda77ed455546c71bf64077afe79feb7f7d5 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 22 Sep 2016 16:29:51 -0500 Subject: [PATCH 132/180] Secondary fix for bad inline filenames Ensures that we're not doing bad partial initialization of string tables by being over-lazy --- symtabAPI/src/Module.C | 2 ++ symtabAPI/src/Object-elf.C | 2 ++ symtabAPI/src/dwarfWalker.C | 17 ++++++++--------- symtabAPI/src/dwarfWalker.h | 3 ++- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 150d7821f1..69e703d320 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -527,6 +527,8 @@ void Module::finalizeOneRange(Address ext_s, Address ext_e) const { void Module::setDebugInfo(Module::DebugInfoT info) { info_.push_back(info); +#if defined(cap_dwarf) +#endif } StringTablePtr & Module::getStrings() { diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 2dbb0ac17f..4d01855d92 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2458,6 +2458,7 @@ bool Object::dwarf_parse_aranges(Dwarf_Debug dbg, std::set& dies_seen Module* m = associated_symtab->getOrCreateModule(modname, actual_start); m->addRange(actual_start, actual_end); m->setDebugInfo(cu_die); + DwarfWalker::buildSrcFiles(dbg, cu_die, m->getStrings()); dies_seen.insert(cu_die_off); dwarf_dealloc(dbg, ranges[i], DW_DLA_ARANGE); } @@ -2511,6 +2512,7 @@ bool Object::fix_global_symbol_modules_static_dwarf() m->addRange(r->first, r->second); } m->setDebugInfo(cu_die); + DwarfWalker::buildSrcFiles(dbg, cu_die, m->getStrings()); dies_seen.insert(cu_die_off); } diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index d83a7cf274..bfa5318ba8 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -226,8 +226,6 @@ bool DwarfWalker::parseModule(Dwarf_Bool is_info, Module *&fixUnknownMod) { if (!fixUnknownMod) fixUnknownMod = mod(); - if (!buildSrcFiles(moduleDIE)) return false; - if (!parse_int(moduleDIE, true)) return false; @@ -249,19 +247,20 @@ void DwarfParseActions::setModuleFromName(std::string moduleName) } } -bool DwarfWalker::buildSrcFiles(Dwarf_Die entry) { +bool DwarfWalker::buildSrcFiles(Dwarf_Debug dbg, Dwarf_Die entry, StringTablePtr srcFiles) { Dwarf_Signed cnt = 0; char** srcFileList; DWARF_ERROR_RET(dwarf_srcfiles(entry, &srcFileList, &cnt, NULL)); - if(!srcFiles()->empty()) return true; // already parsed, the module had better be right. - srcFiles()->push_back("Unknown file"); + if(!srcFiles->empty()) { + return true; + } // already parsed, the module had better be right. + srcFiles->push_back("Unknown file"); for (unsigned i = 0; i < cnt; ++i) { - srcFiles()->push_back(srcFileList[i]); - dwarf_dealloc(dbg(), srcFileList[i], DW_DLA_STRING); + srcFiles->push_back(srcFileList[i]); + dwarf_dealloc(dbg, srcFileList[i], DW_DLA_STRING); } -// cout << "Module " << mod()->fileName() << " srcfiles: " << endl << *srcFiles() << endl; - dwarf_dealloc(dbg(), srcFileList, DW_DLA_LIST); + dwarf_dealloc(dbg, srcFileList, DW_DLA_LIST); return true; } diff --git a/symtabAPI/src/dwarfWalker.h b/symtabAPI/src/dwarfWalker.h index 1ae44838f6..adb3882db1 100644 --- a/symtabAPI/src/dwarfWalker.h +++ b/symtabAPI/src/dwarfWalker.h @@ -239,10 +239,11 @@ namespace Dyninst { // A printable ID for a particular entry unsigned long id() { return (unsigned long) (offset() - compile_offset); } + public: + static bool buildSrcFiles(Dwarf_Debug dbg, Dwarf_Die entry, StringTablePtr strings); private: bool parseCallsite(); - virtual bool buildSrcFiles(Dwarf_Die entry); bool hasDeclaration(bool &decl); bool findTag(); bool findOffset(); From 0fa88965ffa976fa53fc7fb020dfa5444ccc17ef Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 26 Sep 2016 10:57:18 -0500 Subject: [PATCH 133/180] Interfaces to byte-swap ElfData buffers between file and memory order. --- elf/src/Elf_X.C | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index cd175c60f5..75790ebeba 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -47,6 +47,7 @@ #include #include + using namespace std; using boost::crc_32_type; using namespace boost::assign; @@ -904,6 +905,24 @@ void Elf_X_Data::d_align(unsigned int input) { data->d_align = input; } +void Elf_X_Data::xlatetom(unsigned int encode) +{ + if(is64) + { + elf64_xlatetom(data, data, encode); + } else { + elf32_xlatetom(data, data, encode); + } +} +void Elf_X_Data::xlatetof(unsigned int encode) +{ + if(is64) + { + elf64_xlatetof(data, data, encode); + } else { + elf32_xlatetof(data, data, encode); + } +} // Data Interface const char *Elf_X_Data::get_string() const From 4d2a16a98473284b728d6bfd0398af8335e52752 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 30 Sep 2016 15:52:30 -0500 Subject: [PATCH 134/180] Add pure multi-index container implementation of fast interval-based lookup. --- common/h/IBSTree-fast.h | 110 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 4 deletions(-) diff --git a/common/h/IBSTree-fast.h b/common/h/IBSTree-fast.h index fa3a800593..2719a9160b 100644 --- a/common/h/IBSTree-fast.h +++ b/common/h/IBSTree-fast.h @@ -35,13 +35,115 @@ #include #include #include +#include +#include +#include +#include +#include #include + + namespace Dyninst { - template > + template + struct Interval + { + typedef RangeType range_type; + RangeType first; + RangeType second; + template + Interval(T t) { + first = t.startAddr(); + second = t.endAddr(); + } + Interval(RangeType t) + { + first = t; + second = t; + } + Interval(RangeType start, RangeType end) + { + first = start; + second = end; + } + Interval merge(const Interval& other) + { + return Interval(std::min(first, other.first), std::max(second, other.second)); + } + bool operator==(const Interval& rhs) const { + return (first == rhs.first) && (second == rhs.second); + } + bool operator<(const Interval& rhs) const { + return (first < rhs.first) || ((first == rhs.first) && (second < rhs.second)); + } + bool operator==(RangeType off) const { + return ((first <= off) && (off < second)) || + ((first == off) && (off == second)); + } + struct by_low{}; + struct by_high{}; + + }; + template + struct IntervalLookupTraits + { + typedef typename Value::range_type RangeType; + typedef typename Dyninst::Interval IntervalType; + typedef boost::multi_index::composite_key, + boost::multi_index::member > low_key; + typedef boost::multi_index::composite_key, + boost::multi_index::member > high_key; + typedef typename boost::multi_index_container + < + typename Value::Ptr, boost::multi_index::indexed_by< + boost::multi_index::ordered_unique, low_key>, + boost::multi_index::ordered_non_unique, high_key> > + > type; + typedef typename type::value_type value_type; + }; + template + struct IntervalLookup : public IntervalLookupTraits::type + { + typedef IntervalLookupTraits traits; + typedef typename traits::type parent; + typedef typename traits::RangeType RangeType; + + + typedef typename parent::template index::type low_index; + typedef typename parent::template index::type high_index; + typedef typename low_index::const_iterator const_iterator; + typedef typename high_index::const_iterator const_iterator_by_high; + + // First interval overlapping with v + template + const_iterator find(const T& t) const { + auto lower = parent::template get().lower_bound(t); + auto upper = parent::template get().upper_bound(t); + while(lower != upper && lower != parent::end()) + { + if(lower == t) return lower; + ++lower; + } + } + + + template + void copy_equal_range(const T& t, OI iter) const { + auto lower = parent::template get().lower_bound(t); + auto upper = parent::template get().upper_bound(t); + parent candidates_by_high(lower, upper); + auto rng = candidates_by_high.equal_range(t); + std::copy(rng.first, rng.second, iter); + } + }; + + template class IBSTree_fast { + public: typedef typename ITYPE::type interval_type; IBSTree overlapping_intervals; @@ -54,13 +156,12 @@ namespace Dyninst //typedef std::set > interval_set; interval_set unique_intervals; - public: IBSTree_fast() { } ~IBSTree_fast() { - std::cerr << "Fast interval tree had " << unique_intervals.size() << " unique intervals and " << overlapping_intervals.size() << " overlapping" << std::endl; + //std::cerr << "Fast interval tree had " << unique_intervals.size() << " unique intervals and " << overlapping_intervals.size() << " overlapping" << std::endl; } int size() const { @@ -185,6 +286,7 @@ namespace Dyninst unique_intervals.clear(); } - } + + #endif From ff6841140b5d778e804b6f03293c9cee1a6e124a Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 30 Sep 2016 15:59:25 -0500 Subject: [PATCH 135/180] DwarfWalker cleanup --- symtabAPI/src/dwarfWalker.C | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index bfa5318ba8..de0e9caea0 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -707,16 +707,13 @@ vector DwarfWalker::getDieRanges(Dwarf_Debug dbg, Dwarf_Die die, O auto highlow = parseHighPCLowPC(dbg, die); if(highlow.second) newRanges.push_back(highlow.first); - Dwarf_Bool hasRanges = false; - int status = (dwarf_hasattr(die, DW_AT_ranges, &hasRanges, NULL)); - if ((status == DW_DLV_OK) && hasRanges) { Address range_offset; if (findConstant(DW_AT_ranges, range_offset, die, dbg)) { Dwarf_Ranges *ranges = NULL; Dwarf_Signed ranges_length = 0; dwarf_printf("calling ranges_a, offset 0x%lx, die %p\n", range_offset, die); - status = (dwarf_get_ranges_a(dbg, (Dwarf_Off) range_offset, die, + int status = (dwarf_get_ranges_a(dbg, (Dwarf_Off) range_offset, die, &ranges, &ranges_length, NULL, NULL)); bool done = (status != DW_DLV_OK); for (unsigned i = 0; i < ranges_length && !done; i++) { From 5234d515a2cef46d3686b0436705aa26a46686ea Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 30 Sep 2016 16:01:17 -0500 Subject: [PATCH 136/180] Replace all object-elf arch_foo defines with dynamic architecture detection. --- symtabAPI/src/Object-elf.C | 809 +++++++++++++++++++------------------ 1 file changed, 406 insertions(+), 403 deletions(-) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 4d01855d92..8430717f79 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -621,12 +621,19 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, // in section. if (!scn.isFromDebugFile()) { allRegionHdrs.push_back(&scn); + Elf_X_Data data = scn.get_data(); + if(strcmp(name, OPD_NAME) == 0) + { + data.d_type(ELF_T_XWORD); + data.xlatetom(elfHdr->e_endian() ? ELFDATA2MSB : ELFDATA2LSB); + } if(scn.sh_flags() & SHF_ALLOC) { // .bss, etc. have a disk size of 0 unsigned long diskSize = (scn.sh_type() == SHT_NOBITS) ? 0 : scn.sh_size(); + Region *reg = new Region(i, name, scn.sh_addr(), diskSize, scn.sh_addr(), scn.sh_size(), - (mem_image()+scn.sh_offset()), + ((char*)data.d_buf()), getRegionPerms(scn.sh_flags()), getRegionType(scn.sh_type(), scn.sh_flags(), @@ -638,7 +645,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, } else { Region *reg = new Region(i, name, scn.sh_addr(), scn.sh_size(), 0, 0, - (mem_image()+scn.sh_offset()), + ((char*)data.d_buf()), getRegionPerms(scn.sh_flags()), getRegionType(scn.sh_type(), scn.sh_flags(), @@ -762,74 +769,63 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, plt_scnp = scnp; plt_addr_ = scn.sh_addr(); plt_size_ = scn.sh_size(); -#if defined(arch_x86) || defined(arch_x86_64) - // - // On x86, the GNU linker purposefully sets the PLT - // table entry size to an incorrect value to be - // compatible with the UnixWare linker. (See the comment - // in the elf_i386_finish_dynamic_sections function of - // the BFD library.) The GNU linker sets this value to 4, - // when it should be 16. - // - // I see no good way to determine this value from the - // ELF section header information. We can either (a) hard-code - // the value that is used in the BFD library, or (b) compute - // it by dividing the size of the PLT by the number of entries - // we think should be in the PLT. I'm not certain, but I - // believe the PLT and the .rel.plt section should have the - // same number of "real" entries (the x86 PLT has one extra entry - // at the beginning). - // - // This code is applicable to any x86 system that uses the - // GNU linker. We currently only support Linux on x86 - if - // we start supporting some other x86 OS that uses the GNU - // linker in the future, it should be enabled for that platform as well. - // Note that this problem does not affect the non-x86 platforms - // that might use the GNU linker. For example, programs linked - // with gld on SPARC Solaris have the correct PLT entry size. - // - // Another potential headache in the future is if we support - // some other x86 platform that has both the GNU linker and - // some other linker. (Does BSD fall into this category?) - // If the two linkers set the entry size differently, we may - // need to re-evaluate this code. - // - //plt_entry_size_ = plt_size_ / ((rel_plt_size_ / rel_plt_entry_size_) + 1); - plt_entry_size_ = 16; - assert( plt_entry_size_ == 16 ); -#else - plt_entry_size_ = scn.sh_entsize(); - - // X86-64: if we're on a 32-bit binary then set the PLT entry size to 16 - // as above -#if defined(arch_x86_64) - if (addressWidth_nbytes == 4) { - plt_entry_size_ = 16; - assert( plt_entry_size_ == 16 ); - } - else { - assert(addressWidth_nbytes == 8); - } -#endif - - -#if defined (ppc32_linux) || defined(ppc32_bgp) - if (scn.sh_flags() & SHF_EXECINSTR) { - // Old style executable PLT - if (!plt_entry_size_) - plt_entry_size_ = 8; - else { - if (plt_entry_size_ != 8) - create_printf("%s[%d]: weird plt_entry_size_ is %d, not 8\n", - FILE__, __LINE__, plt_entry_size_); - } + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { + // + // On x86, the GNU linker purposefully sets the PLT + // table entry size to an incorrect value to be + // compatible with the UnixWare linker. (See the comment + // in the elf_i386_finish_dynamic_sections function of + // the BFD library.) The GNU linker sets this value to 4, + // when it should be 16. + // + // I see no good way to determine this value from the + // ELF section header information. We can either (a) hard-code + // the value that is used in the BFD library, or (b) compute + // it by dividing the size of the PLT by the number of entries + // we think should be in the PLT. I'm not certain, but I + // believe the PLT and the .rel.plt section should have the + // same number of "real" entries (the x86 PLT has one extra entry + // at the beginning). + // + // This code is applicable to any x86 system that uses the + // GNU linker. We currently only support Linux on x86 - if + // we start supporting some other x86 OS that uses the GNU + // linker in the future, it should be enabled for that platform as well. + // Note that this problem does not affect the non-x86 platforms + // that might use the GNU linker. For example, programs linked + // with gld on SPARC Solaris have the correct PLT entry size. + // + // Another potential headache in the future is if we support + // some other x86 platform that has both the GNU linker and + // some other linker. (Does BSD fall into this category?) + // If the two linkers set the entry size differently, we may + // need to re-evaluate this code. + // + //plt_entry_size_ = plt_size_ / ((rel_plt_size_ / rel_plt_entry_size_) + 1); + plt_entry_size_ = 16; + assert(plt_entry_size_ == 16); + } + else + { + plt_entry_size_ = scn.sh_entsize(); + if(getArch() == Dyninst::Arch_ppc32) + { + if (scn.sh_flags() & SHF_EXECINSTR) { + // Old style executable PLT + if (!plt_entry_size_) + plt_entry_size_ = 8; + else { + if (plt_entry_size_ != 8) + create_printf("%s[%d]: weird plt_entry_size_ is %d, not 8\n", + FILE__, __LINE__, plt_entry_size_); + } - } else { - // New style secure PLT - plt_entry_size_ = 16; - } -#endif -#endif + } else { + // New style secure PLT + plt_entry_size_ = 16; + } + } + } } else if (strcmp(name, COMMENT_NAME) == 0) { /* comment section is a sequence of NULL-terminated strings. We want to concatenate them and search for BGP to determine @@ -1089,349 +1085,352 @@ bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, if( reldata.isValid() && symdata.isValid() && strdata.isValid() ) { Offset next_plt_entry_addr = plt_addr_; - -#if defined(arch_x86) || defined(arch_x86_64) + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) + { next_plt_entry_addr += plt_entry_size_; // 1st PLT entry is special - -#elif defined (ppc32_linux) || defined(ppc32_bgp) + } + else if(getArch()==Dyninst::Arch_ppc32) + { bool extraStubs = false; - // Sanity check. - if (!plt_entry_size_) { - create_printf("%s[%d]: FIXME: plt_entry_size not established\n", FILE__, __LINE__); - plt_entry_size_ = 8; - } - - if (plt_entry_size_ == 8) { - // Old style executable PLT section - next_plt_entry_addr += 9*plt_entry_size_; // 1st 9 PLT entries are special - - } else if (plt_entry_size_ == 16) { - // New style secure PLT - Region *plt = NULL, *relplt = NULL, *dynamic = NULL, - *got = NULL, *glink = NULL; - unsigned int glink_addr = 0; - unsigned int stub_addr = 0; - - // Find the GLINK section. See ppc_elf_get_synthetic_symtab() in - // bfd/elf32-ppc.c of GNU's binutils for more information. - - for (unsigned iter = 0; iter < regions_.size(); ++iter) { - std::string name = regions_[iter]->getRegionName(); - if (name == PLT_NAME) plt = regions_[iter]; - else if (name == REL_PLT_NAME) relplt = regions_[iter]; - else if (name == DYNAMIC_NAME) dynamic = regions_[iter]; - else if (name == GOT_NAME) got = regions_[iter]; - } - - // Rely on .dynamic section for prelinked binaries. - if (dynamic != NULL) { - Elf32_Dyn *dyn = (Elf32_Dyn *)dynamic->getPtrToRawData(); - unsigned int count = dynamic->getMemSize() / sizeof(Elf32_Dyn); - - for (unsigned int i = 0; i < count; ++i) { - // Use DT_LOPROC instead of DT_PPC_GOT to circumvent problems - // caused by early versions of libelf where DT_PPC_GOT has - // yet to be defined. - if (dyn[i].d_tag == DT_LOPROC) { - unsigned int g_o_t = dyn[i].d_un.d_val; - if (got != NULL) { - unsigned char *data = - (unsigned char *)got->getPtrToRawData(); - glink_addr = *(unsigned int *) - (data + (g_o_t - got->getMemOffset() + 4)); - break; - } - } - } - } + // Sanity check. + if (!plt_entry_size_) { + create_printf("%s[%d]: FIXME: plt_entry_size not established\n", FILE__, __LINE__); + plt_entry_size_ = 8; + } - // Otherwise, first entry in .plt section holds the glink address - if (glink_addr == 0) { - unsigned char *data = (unsigned char *)plt->getPtrToRawData(); - glink_addr = *(unsigned int *)(data); - } + if (plt_entry_size_ == 8) { + // Old style executable PLT section + next_plt_entry_addr += 9*plt_entry_size_; // 1st 9 PLT entries are special + + } else if (plt_entry_size_ == 16) { + // New style secure PLT + Region *plt = NULL, *relplt = NULL, *dynamic = NULL, + *got = NULL, *glink = NULL; + unsigned int glink_addr = 0; + unsigned int stub_addr = 0; + + // Find the GLINK section. See ppc_elf_get_synthetic_symtab() in + // bfd/elf32-ppc.c of GNU's binutils for more information. + + for (unsigned iter = 0; iter < regions_.size(); ++iter) { + std::string name = regions_[iter]->getRegionName(); + if (name == PLT_NAME) plt = regions_[iter]; + else if (name == REL_PLT_NAME) relplt = regions_[iter]; + else if (name == DYNAMIC_NAME) dynamic = regions_[iter]; + else if (name == GOT_NAME) got = regions_[iter]; + } - // Search for region that contains glink address - for (unsigned iter = 0; iter < regions_.size(); ++iter) { - unsigned int start = regions_[iter]->getMemOffset(); - unsigned int end = start + regions_[iter]->getMemSize(); - if (start <= glink_addr && glink_addr < end) { - glink = regions_[iter]; - break; - } - } + // Rely on .dynamic section for prelinked binaries. + if (dynamic != NULL) { + Elf32_Dyn *dyn = (Elf32_Dyn *)dynamic->getPtrToRawData(); + unsigned int count = dynamic->getMemSize() / sizeof(Elf32_Dyn); + + for (unsigned int i = 0; i < count; ++i) { + // Use DT_LOPROC instead of DT_PPC_GOT to circumvent problems + // caused by early versions of libelf where DT_PPC_GOT has + // yet to be defined. + if (dyn[i].d_tag == DT_LOPROC) { + unsigned int g_o_t = dyn[i].d_un.d_val; + if (got != NULL) { + unsigned char *data = + (unsigned char *)got->getPtrToRawData(); + glink_addr = *(unsigned int *) + (data + (g_o_t - got->getMemOffset() + 4)); + break; + } + } + } + } - if (!glink) { - return false; - } + // Otherwise, first entry in .plt section holds the glink address + if (glink_addr == 0) { + unsigned char *data = (unsigned char *)plt->getPtrToRawData(); + glink_addr = *(unsigned int *)(data); + } - // Find PLT function stubs. They preceed the glink section. - stub_addr = glink_addr - (rel_plt_size_/rel_plt_entry_size_) * 16; - - const unsigned int LWZ_11_30 = 0x817e0000; - const unsigned int ADDIS_11_30 = 0x3d7e0000; - const unsigned int LWZ_11_11 = 0x816b0000; - const unsigned int MTCTR_11 = 0x7d6903a6; - const unsigned int BCTR = 0x4e800420; - - unsigned char *sec_data = (unsigned char *)glink->getPtrToRawData(); - unsigned int *insn = (unsigned int *) - (sec_data + (stub_addr - glink->getMemOffset())); - - // Keep moving pointer back if more -fPIC stubs are found. - while (sec_data < (unsigned char *)insn) { - unsigned int *back = insn - 4; - - if (( (back[0] & 0xffff0000) == LWZ_11_30 - && back[1] == MTCTR_11 - && back[2] == BCTR) - - || ( (back[0] & 0xffff0000) == ADDIS_11_30 - && (back[1] & 0xffff0000) == LWZ_11_11 - && back[2] == MTCTR_11 - && back[3] == BCTR)) - { - extraStubs = true; - stub_addr -= 16; - insn = back; - } else { - break; - } - } + // Search for region that contains glink address + for (unsigned iter = 0; iter < regions_.size(); ++iter) { + unsigned int start = regions_[iter]->getMemOffset(); + unsigned int end = start + regions_[iter]->getMemSize(); + if (start <= glink_addr && glink_addr < end) { + glink = regions_[iter]; + break; + } + } - // Okay, this is where things get hairy. If we have a one to one - // relationship between the glink stubs and plt entries (meaning - // extraStubs == false), then we can generate our relocationEntry - // objects normally below. - - // However, if we have extra glink stubs, then we must generate - // relocations with unknown destinations for *all* stubs. Then, - // we use the loop below to store additional information about - // the data plt entry keyed by plt entry address. - - // Finally, if a symbol with any of the following forms: - // [hex_addr].got2.plt_pic32.[sym_name] - // [hex_addr].plt_pic32.[sym_name] - // - // matches the glink stub address, then stub symbols exist and we - // can rely on these tell us where the stub will eventually go. - - if (extraStubs == true) { - std::string name; - relocationEntry re; - - while (stub_addr < glink_addr) { - if (symsByOffset_.find(stub_addr) != symsByOffset_.end()) { - name = (symsByOffset_[stub_addr])[0]->getMangledName(); - name = name.substr( name.rfind("plt_pic32.") + 10 ); - } - - if (!name.empty()) { - re = relocationEntry( stub_addr, 0, name, NULL, 0 ); - } else { - re = relocationEntry( stub_addr, 0, "@plt", NULL, 0 ); - } - fbt_.push_back(re); - stub_addr += 16; - } - - // Now prepare to iterate over plt below. - next_plt_entry_addr = plt_addr_; - plt_entry_size_ = 4; - - } else { - next_plt_entry_addr = stub_addr; - } + if (!glink) { + return false; + } - } else { - create_printf("ERROR: Can't handle %d PLT entry size\n", - plt_entry_size_); - return false; - } + // Find PLT function stubs. They preceed the glink section. + stub_addr = glink_addr - (rel_plt_size_/rel_plt_entry_size_) * 16; - // actually this is just fudged to make the offset value 72, which is what binutils uses - // Note that binutils makes the distinction between PLT_SLOT_SIZE (8), - // and PLT_ENTRY_SIZE (12). PLT_SLOT_SIZE seems to be what we want, even though we also - // have PLT_INITIAL_ENTRY_SIZE (72) - // see binutils/bfd/elf32-ppc.c/h if more info is needed - //next_plt_entry_addr += 72; // 1st 6 PLT entries art special - -#elif defined(arch_power) && defined(arch_64bit) && defined(os_linux) - // Unlike PPC32 Linux, we don't have a deterministic way of finding - // PPC64 Linux linker stubs. So, we'll wait until the CFG is built - // inside Dyninst, and code read at that point. To find them at this - // point would require a scan of the entire .text section. - // - // If we're lucky, symbols may exist for these linker stubs. They will - // come in the following forms: - // [hex_addr].plt_call.[sym_name] - // [hex_addr].plt_branch.[sym_name] - // [hex_addr].long_branch.[sym_name] - // [hex_addr].plt_branch_r2off.[sym_name] - // [hex_addr].long_branch_r2off.[sym_name] - // - // Again unlike PPC32 above, we have no glink stub address to compare - // against, so we must search through all symbols to find these names. - // - - // First, build a map of the .rela.plt symbol name -> .rela.plt offset: - dyn_hash_map plt_rel_map; - - // I'm not a fan of code duplication, but merging this into the - // loop below would be ugly and difficult to maintain. - Elf_X_Sym _sym = symdata.get_sym(); - Elf_X_Rel _rel = reldata.get_rel(); - Elf_X_Rela _rela = reldata.get_rela(); - const char *_strs = strdata.get_string(); - - for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { - long _offset; - long _index; - - switch (reldata.d_type()) { - case ELF_T_REL: - _offset = _rel.r_offset(i); - _index = _rel.R_SYM(i); - break; - - case ELF_T_RELA: - _offset = _rela.r_offset(i); - _index = _rela.R_SYM(i); - break; - - default: - // We should never reach this case. - return false; - }; - - std::string _name = &_strs[ _sym.st_name(_index) ]; - // I'm interested to see if this assert will ever fail. - assert(_name.length()); - - plt_rel_map[_name] = _offset; - } - // End code duplication. - - dyn_hash_map >::iterator iter; - for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { - std::string name = iter->first; - if (name.length() > 8) { - if (name.substr(8, 10) == ".plt_call.") - name = name.substr(8 + 10); - else if (name.substr(8, 12) == ".plt_branch.") - name = name.substr(8 + 12); - else if (name.substr(8, 13) == ".long_branch.") - name = name.substr(8 + 13); - else if (name.substr(8, 18) == ".plt_branch_r2off.") - name = name.substr(8 + 18); - else if (name.substr(8, 19) == ".long_branch_r2off.") - name = name.substr(8 + 19); - else - continue; - - // Remove possible trailing addend value. - std::string::size_type pos = name.rfind('+'); - if (pos != std::string::npos) name.erase(pos); - - // Remove possible version number. - pos = name.find('@'); - if (pos != std::string::npos) name.erase(pos); - - // Find the dynamic symbol this linker stub branches to. - Symbol *targ_sym = NULL; - if (symbols_.find(name) != symbols_.end()) - for (unsigned i = 0; i < symbols_[name].size(); ++i) - if ( (symbols_[name])[i]->isInDynSymtab()) - targ_sym = (symbols_[name])[i]; - - // If a corresponding target symbol cannot be found for a - // named linker stub, then ignore it. We'll find it during - // parsing. - if (!targ_sym) continue; - - if (iter->second.size() != 1) - continue; - dyn_hash_map::iterator pltrel_iter = plt_rel_map.find(name); - if (pltrel_iter == plt_rel_map.end()) - continue; - - Symbol *stub_sym = iter->second[0]; - relocationEntry re(stub_sym->getOffset(), - pltrel_iter->second, - name, - targ_sym); - fbt_.push_back(re); - } - } + const unsigned int LWZ_11_30 = 0x817e0000; + const unsigned int ADDIS_11_30 = 0x3d7e0000; + const unsigned int LWZ_11_11 = 0x816b0000; + const unsigned int MTCTR_11 = 0x7d6903a6; + const unsigned int BCTR = 0x4e800420; - // 1st plt entry is special. - next_plt_entry_addr += plt_entry_size_; + unsigned char *sec_data = (unsigned char *)glink->getPtrToRawData(); + unsigned int *insn = (unsigned int *) + (sec_data + (stub_addr - glink->getMemOffset())); -#elif defined(arch_aarch64) - // For ARM, the first entry should be skipped, - // but the first entry is in double size - next_plt_entry_addr += 2 * plt_entry_size_; -#else - next_plt_entry_addr += 4*(plt_entry_size_); //1st 4 entries are special -#endif + // Keep moving pointer back if more -fPIC stubs are found. + while (sec_data < (unsigned char *)insn) { + unsigned int *back = insn - 4; - Elf_X_Sym sym = symdata.get_sym(); - Elf_X_Rel rel = reldata.get_rel(); - Elf_X_Rela rela = reldata.get_rela(); - const char *strs = strdata.get_string(); - - if (sym.isValid() && (rel.isValid() || rela.isValid()) && strs) { - - // Sometimes, PPC32 Linux may use this loop to update fbt entries. - // Should stay -1 for all other platforms. See notes above. - int fbt_iter = -1; - if (fbt_.size() > 0 && !fbt_[0].rel_addr() && fbt_[0].name() != "@plt") - fbt_iter = 0; - - for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { - long offset; - long addend; - long index; - unsigned long type; - Region::RegionType rtype; - - switch (reldata.d_type()) { - case ELF_T_REL: - offset = rel.r_offset(i); - addend = 0; - index = rel.R_SYM(i); - type = rel.R_TYPE(i); - rtype = Region::RT_REL; - break; + if (( (back[0] & 0xffff0000) == LWZ_11_30 + && back[1] == MTCTR_11 + && back[2] == BCTR) - case ELF_T_RELA: - offset = rela.r_offset(i); - addend = rela.r_addend(i); - index = rela.R_SYM(i); - type = rela.R_TYPE(i); - rtype = Region::RT_RELA; - break; + || ( (back[0] & 0xffff0000) == ADDIS_11_30 + && (back[1] & 0xffff0000) == LWZ_11_11 + && back[2] == MTCTR_11 + && back[3] == BCTR)) + { + extraStubs = true; + stub_addr -= 16; + insn = back; + } else { + break; + } + } - default: - // We should never reach this case. - return false; - }; + // Okay, this is where things get hairy. If we have a one to one + // relationship between the glink stubs and plt entries (meaning + // extraStubs == false), then we can generate our relocationEntry + // objects normally below. + + // However, if we have extra glink stubs, then we must generate + // relocations with unknown destinations for *all* stubs. Then, + // we use the loop below to store additional information about + // the data plt entry keyed by plt entry address. + + // Finally, if a symbol with any of the following forms: + // [hex_addr].got2.plt_pic32.[sym_name] + // [hex_addr].plt_pic32.[sym_name] + // + // matches the glink stub address, then stub symbols exist and we + // can rely on these tell us where the stub will eventually go. + + if (extraStubs == true) { + std::string name; + relocationEntry re; + + while (stub_addr < glink_addr) { + if (symsByOffset_.find(stub_addr) != symsByOffset_.end()) { + name = (symsByOffset_[stub_addr])[0]->getMangledName(); + name = name.substr( name.rfind("plt_pic32.") + 10 ); + } - std::string targ_name = &strs[ sym.st_name(index) ]; - vector dynsym_list; - if (symbols_.find(targ_name) != symbols_.end()) - { - vector &syms = symbols_[&strs[ sym.st_name(index)]]; - for (vector::iterator i = syms.begin(); i != syms.end(); i++) { - if (!(*i)->isInDynSymtab()) - continue; - dynsym_list.push_back(*i); + if (!name.empty()) { + re = relocationEntry( stub_addr, 0, name, NULL, 0 ); + } else { + re = relocationEntry( stub_addr, 0, "@plt", NULL, 0 ); } + fbt_.push_back(re); + stub_addr += 16; } - else { - dynsym_list.clear(); + + // Now prepare to iterate over plt below. + next_plt_entry_addr = plt_addr_; + plt_entry_size_ = 4; + + } else { + next_plt_entry_addr = stub_addr; + } + + } else { + create_printf("ERROR: Can't handle %d PLT entry size\n", + plt_entry_size_); + return false; + } + + // actually this is just fudged to make the offset value 72, which is what binutils uses + // Note that binutils makes the distinction between PLT_SLOT_SIZE (8), + // and PLT_ENTRY_SIZE (12). PLT_SLOT_SIZE seems to be what we want, even though we also + // have PLT_INITIAL_ENTRY_SIZE (72) + // see binutils/bfd/elf32-ppc.c/h if more info is needed + //next_plt_entry_addr += 72; // 1st 6 PLT entries art special + + + } else if(getArch() == Dyninst::Arch_ppc64) + { + // Unlike PPC32 Linux, we don't have a deterministic way of finding + // PPC64 Linux linker stubs. So, we'll wait until the CFG is built + // inside Dyninst, and code read at that point. To find them at this + // point would require a scan of the entire .text section. + // + // If we're lucky, symbols may exist for these linker stubs. They will + // come in the following forms: + // [hex_addr].plt_call.[sym_name] + // [hex_addr].plt_branch.[sym_name] + // [hex_addr].long_branch.[sym_name] + // [hex_addr].plt_branch_r2off.[sym_name] + // [hex_addr].long_branch_r2off.[sym_name] + // + // Again unlike PPC32 above, we have no glink stub address to compare + // against, so we must search through all symbols to find these names. + // + + // First, build a map of the .rela.plt symbol name -> .rela.plt offset: + dyn_hash_map plt_rel_map; + + // I'm not a fan of code duplication, but merging this into the + // loop below would be ugly and difficult to maintain. + Elf_X_Sym _sym = symdata.get_sym(); + Elf_X_Rel _rel = reldata.get_rel(); + Elf_X_Rela _rela = reldata.get_rela(); + const char *_strs = strdata.get_string(); + + for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { + long _offset; + long _index; + + switch (reldata.d_type()) { + case ELF_T_REL: + _offset = _rel.r_offset(i); + _index = _rel.R_SYM(i); + break; + + case ELF_T_RELA: + _offset = _rela.r_offset(i); + _index = _rela.R_SYM(i); + break; + + default: + // We should never reach this case. + return false; + }; + + std::string _name = &_strs[ _sym.st_name(_index) ]; + // I'm interested to see if this assert will ever fail. + assert(_name.length()); + + plt_rel_map[_name] = _offset; + } + // End code duplication. + + dyn_hash_map >::iterator iter; + for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { + std::string name = iter->first; + if (name.length() > 8) { + if (name.substr(8, 10) == ".plt_call.") + name = name.substr(8 + 10); + else if (name.substr(8, 12) == ".plt_branch.") + name = name.substr(8 + 12); + else if (name.substr(8, 13) == ".long_branch.") + name = name.substr(8 + 13); + else if (name.substr(8, 18) == ".plt_branch_r2off.") + name = name.substr(8 + 18); + else if (name.substr(8, 19) == ".long_branch_r2off.") + name = name.substr(8 + 19); + else + continue; + + // Remove possible trailing addend value. + std::string::size_type pos = name.rfind('+'); + if (pos != std::string::npos) name.erase(pos); + + // Remove possible version number. + pos = name.find('@'); + if (pos != std::string::npos) name.erase(pos); + + // Find the dynamic symbol this linker stub branches to. + Symbol *targ_sym = NULL; + if (symbols_.find(name) != symbols_.end()) + for (unsigned i = 0; i < symbols_[name].size(); ++i) + if ( (symbols_[name])[i]->isInDynSymtab()) + targ_sym = (symbols_[name])[i]; + + // If a corresponding target symbol cannot be found for a + // named linker stub, then ignore it. We'll find it during + // parsing. + if (!targ_sym) continue; + + if (iter->second.size() != 1) + continue; + dyn_hash_map::iterator pltrel_iter = plt_rel_map.find(name); + if (pltrel_iter == plt_rel_map.end()) + continue; + + Symbol *stub_sym = iter->second[0]; + relocationEntry re(stub_sym->getOffset(), + pltrel_iter->second, + name, + targ_sym); + fbt_.push_back(re); + } + } + + // 1st plt entry is special. + next_plt_entry_addr += plt_entry_size_; + + } else if (getArch() == Dyninst::Arch_aarch64) + { + next_plt_entry_addr += 2 * plt_entry_size_; + } else { + next_plt_entry_addr += 4*(plt_entry_size_); //1st 4 entries are special + } + + + Elf_X_Sym sym = symdata.get_sym(); + Elf_X_Rel rel = reldata.get_rel(); + Elf_X_Rela rela = reldata.get_rela(); + const char *strs = strdata.get_string(); + + if (sym.isValid() && (rel.isValid() || rela.isValid()) && strs) { + + // Sometimes, PPC32 Linux may use this loop to update fbt entries. + // Should stay -1 for all other platforms. See notes above. + int fbt_iter = -1; + if (fbt_.size() > 0 && !fbt_[0].rel_addr() && fbt_[0].name() != "@plt") + fbt_iter = 0; + + for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { + long offset; + long addend; + long index; + unsigned long type; + Region::RegionType rtype; + + switch (reldata.d_type()) { + case ELF_T_REL: + offset = rel.r_offset(i); + addend = 0; + index = rel.R_SYM(i); + type = rel.R_TYPE(i); + rtype = Region::RT_REL; + break; + + case ELF_T_RELA: + offset = rela.r_offset(i); + addend = rela.r_addend(i); + index = rela.R_SYM(i); + type = rela.R_TYPE(i); + rtype = Region::RT_RELA; + break; + + default: + // We should never reach this case. + return false; + }; + + std::string targ_name = &strs[ sym.st_name(index) ]; + vector dynsym_list; + if (symbols_.find(targ_name) != symbols_.end()) + { + vector &syms = symbols_[&strs[ sym.st_name(index)]]; + for (vector::iterator i = syms.begin(); i != syms.end(); i++) { + if (!(*i)->isInDynSymtab()) + continue; + dynsym_list.push_back(*i); } + } + else { + dynsym_list.clear(); + } #if defined(os_vxworks) // VxWorks Kernel Images don't use PLT's, but we'll use the fbt to @@ -1541,11 +1540,14 @@ void Object::load_object(bool alloc_syms) } get_valid_memory_areas(*elfHdr); -#if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64)) - if (eh_frame_scnp != 0 && gcc_except != 0) +#if (defined(os_linux) || defined(os_freebsd)) + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { - find_catch_blocks(eh_frame_scnp, gcc_except, - txtaddr, dataddr, catch_addrs_); + if (eh_frame_scnp != 0 && gcc_except != 0) + { + find_catch_blocks(eh_frame_scnp, gcc_except, + txtaddr, dataddr, catch_addrs_); + } } #endif if (interp_scnp) { @@ -1727,10 +1729,12 @@ void Object::load_shared_object(bool alloc_syms) get_valid_memory_areas(*elfHdr); -#if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64)) - if (eh_frame_scnp != 0 && gcc_except != 0) { - find_catch_blocks(eh_frame_scnp, gcc_except, - txtaddr, dataddr, catch_addrs_); +#if (defined(os_linux) || defined(os_freebsd)) + if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { + if (eh_frame_scnp != 0 && gcc_except != 0) { + find_catch_blocks(eh_frame_scnp, gcc_except, + txtaddr, dataddr, catch_addrs_); + } } #endif @@ -1952,7 +1956,6 @@ void Object::parse_opd(Elf_X_Shdr *opd_hdr) { // Let's read this puppy unsigned long *buf = (unsigned long *)data.d_buf(); - // In some cases, the OPD is a set of 3-tuples: . // In others, it's a set of 2-tuples. Since we can't tell the difference, we // instead look for function offsets. @@ -3115,7 +3118,7 @@ bool parseCompilerType(Object *objPtr) #endif -#if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64)) +#if (defined(os_linux) || defined(os_freebsd)) static unsigned long read_uleb128(const unsigned char *data, unsigned *bytes_read) { From c42859c305b2217a0737dd77930f729a70ecdd7c Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Fri, 30 Sep 2016 16:09:34 -0500 Subject: [PATCH 137/180] Refactor module lookup implementation Remove dead code Fix up default module construction --- symtabAPI/h/LineInformation.h | 4 +- symtabAPI/h/Module.h | 71 ++++----- symtabAPI/h/RangeLookup.h | 29 ++-- symtabAPI/h/Symtab.h | 32 ++-- symtabAPI/src/LineInformation.C | 40 +++-- symtabAPI/src/Module.C | 30 +--- symtabAPI/src/Object-elf.C | 32 ++-- symtabAPI/src/Symtab-edit.C | 42 ++--- symtabAPI/src/Symtab-lookup.C | 150 +++++++++++++---- symtabAPI/src/Symtab.C | 275 +++++++------------------------- 10 files changed, 324 insertions(+), 381 deletions(-) diff --git a/symtabAPI/h/LineInformation.h b/symtabAPI/h/LineInformation.h index 9f421502f0..e8d81e86d0 100644 --- a/symtabAPI/h/LineInformation.h +++ b/symtabAPI/h/LineInformation.h @@ -48,8 +48,8 @@ class SYMTAB_EXPORT LineInformation : public: typedef RangeLookupTypes< Statement> traits; typedef RangeLookupTypes< Statement >::type impl_t; - typedef traits::addr_range_index::const_iterator const_iterator; - typedef traits::line_info_index::const_iterator const_line_info_iterator; + typedef impl_t::index::type::const_iterator const_iterator; + typedef impl_t::index::type::const_iterator const_line_info_iterator; typedef traits::value_type Statement_t; LineInformation(); diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 22e7b11b64..056a8048da 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -55,25 +55,22 @@ class localVar; class Symtab; -class SYMTAB_EXPORT Statement +class SYMTAB_EXPORT Statement : public AddressRange { friend class Module; friend class LineInformation; Statement(int file_index, unsigned int line, unsigned int col = 0, Offset start_addr = (Offset) -1L, Offset end_addr = (Offset) -1L) : + AddressRange(start_addr, end_addr), file_index_(file_index), line_(line), - column_(col), - start_addr_(start_addr), - end_addr_(end_addr) + column_(col) { } unsigned int file_index_; // Maybe this should be module? unsigned int line_; unsigned int column_; - Offset start_addr_; - Offset end_addr_; StringTablePtr strings_; public: StringTablePtr getStrings_() const; @@ -82,7 +79,7 @@ class SYMTAB_EXPORT Statement public: - Statement() : file_index_(0), line_(0), column_(0), start_addr_(0), end_addr_(0) {} + Statement() : AddressRange(0,0), file_index_(0), line_(0), column_(0) {} struct StatementLess { bool operator () ( const Statement &lhs, const Statement &rhs ) const; }; @@ -92,10 +89,7 @@ class SYMTAB_EXPORT Statement bool operator==(const Statement &cmp) const; // bool operator==(const char* file) const {return strcmp(file, first) == 0; } bool operator==(Offset addr) const { - if(startAddr() == endAddr()) { - return addr == startAddr(); - } - return (startAddr() <= addr) && (addr < endAddr()); + return AddressRange::contains(addr); } bool operator<(Offset addr) const { return startAddr() <= addr; @@ -105,14 +99,15 @@ class SYMTAB_EXPORT Statement } ~Statement() {} - Offset startAddr() const { return start_addr_;} - Offset endAddr() const {return end_addr_;} + Offset startAddr() const { return first;} + Offset endAddr() const {return second;} std::string getFile() const; unsigned int getFileIndex() const { return file_index_; } unsigned int getLine()const {return line_;} unsigned int getColumn() const { return column_; } - AddressRange addressRange( ) const { return AddressRange(*this); } - bool contains(Offset addr) const { return addressRange().contains(addr); } + struct addr_range {}; + struct line_info {}; + struct upper_bound {}; typedef boost::shared_ptr Ptr; typedef boost::shared_ptr ConstPtr; @@ -233,9 +228,11 @@ typedef Statement LineNoTuple; bool setLineInfo(Dyninst::SymtabAPI::LineInformation *lineInfo); void addRange(Dyninst::Address low, Dyninst::Address high); - void setDebugInfo(Module::DebugInfoT info); - void finalizeRanges(); - private: + void addDebugInfo(Module::DebugInfoT info); + + void finalizeRanges(); + + private: Dyninst::SymtabAPI::LineInformation* lineInfo_; typeCollection* typeInfo_; std::vector info_; @@ -271,49 +268,43 @@ typedef Statement LineNoTuple; } -struct ModRange : public interval +struct ModRange : public Dyninst::Interval { + typedef Dyninst::Interval parent; ModRange(Offset l, Offset h, Module* m) : - low_(l), high_(h), mod_(m) + Dyninst::Interval(l, h), mod_(m) {} bool operator==(const ModRange &rhs) const { - return low_ == rhs.low_ && - high_ == rhs.high_ && - mod_ == rhs.mod_; + return (parent::operator==(rhs)) && (mod_ == rhs.mod_); } bool operator!=(const ModRange &rhs) const { return !(rhs == *this); } bool contains(const ModRange& rhs) const { - return (rhs.low() >= low()) && - (rhs.high() <= high()) && - (rhs.mod() == mod() ); + return (rhs.first >= first) && + (rhs.second <= second) && + (rhs.mod() == mod()); + } + bool operator==(Offset off) const { + return parent::operator==(off); } - - Offset low() const { return low_; } - Offset high() const { return high_; } Module* mod() const { return mod_;} - Offset low_; - Offset high_; Module* mod_; + typedef ModRange* Ptr; }; - - template + template OS& operator<<(OS& os, const ModRange& m) { - os << m.mod() << ": [" << m.low() << ", " << m.high() << ")"; - return os; - } - template - OS& operator<<(OS& os, ModRange* m) - { - os << *m; + os << m.mod() << ": [" << m.first << ", " << m.second << ")"; return os; } + }//namespace SymtabAPI }//namespace Dyninst + + #endif diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index f7df9d3926..a103aa9f16 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -56,6 +56,16 @@ namespace Dyninst { first = t.startAddr(); second = t.endAddr(); } + template + AddressRange(typename boost::shared_ptr t) { + first = t->startAddr(); + second = t->endAddr(); + } + template + AddressRange(T* t) { + first = t->startAddr(); + second = t->endAddr(); + } AddressRange(Offset t) { first = t; @@ -84,10 +94,9 @@ namespace Dyninst { template struct RangeLookupTypes { - struct addr_range {}; - struct line_info {}; - struct upper_bound {}; - typedef typename boost::multi_index::const_mem_fun + typedef typename boost::multi_index::composite_key, + boost::multi_index::const_mem_fun > addr_range_key; typedef typename boost::multi_index::composite_key, @@ -101,14 +110,14 @@ namespace Dyninst { < typename Value::Ptr, boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< boost::multi_index::tag, addr_range_key>, - boost::multi_index::ordered_non_unique< boost::multi_index::tag, upper_bound_key>, - boost::multi_index::ordered_non_unique< boost::multi_index::tag, line_info_key > + boost::multi_index::ordered_unique< boost::multi_index::tag, addr_range_key>, + boost::multi_index::ordered_non_unique< boost::multi_index::tag, upper_bound_key>, + boost::multi_index::ordered_non_unique< boost::multi_index::tag, line_info_key > > > type; - typedef typename boost::multi_index::index::type addr_range_index; - typedef typename boost::multi_index::index::type upper_bound_index; - typedef typename boost::multi_index::index::type line_info_index; + typedef typename boost::multi_index::index::type addr_range_index; + typedef typename boost::multi_index::index::type upper_bound_index; + typedef typename boost::multi_index::index::type line_info_index; typedef typename type::value_type value_type; diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index 4a229bcf16..35c973d135 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -51,6 +51,7 @@ #include #include #include +#include using boost::multi_index_container; using boost::multi_index::indexed_by; using boost::multi_index::ordered_unique; @@ -86,7 +87,7 @@ class FunctionBase; class FuncRange; class ModRange; -typedef IBSTree_fast ModRangeLookup; +typedef IntervalLookup< ModRange > ModRangeLookup; typedef IBSTree FuncRangeLookup; typedef Dyninst::ProcessReader MemRegReader; @@ -130,16 +131,7 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, static Symtab *findOpenSymtab(std::string filename); static bool closeSymtab(Symtab *); - Serializable * serialize_impl(SerializerBase *sb, - const char *tag = "Symtab") THROW_SPEC (SerializerError); - void rebuild_symbol_hashes(SerializerBase *); - void rebuild_funcvar_hashes(SerializerBase *); - void rebuild_module_hashes(SerializerBase *); - void rebuild_region_indexes(SerializerBase *) THROW_SPEC(SerializerError); - static bool setup_module_up_ptrs(SerializerBase *,Symtab *st); - static bool fixup_relocation_symbols(SerializerBase *,Symtab *st); - - bool exportXML(std::string filename); + bool exportXML(std::string filename); bool exportBin(std::string filename); static Symtab *importBin(std::string filename); bool getRegValueAtFrame(Address pc, @@ -557,9 +549,21 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, std::vector everyVariable; dyn_hash_map varsByOffset; - dyn_hash_map modsByFileName; - dyn_hash_map modsByFullName; - std::vector _mods; + + boost::multi_index_container, + boost::multi_index::ordered_unique >, + boost::multi_index::ordered_non_unique< + boost::multi_index::const_mem_fun >, + boost::multi_index::ordered_non_unique< + boost::multi_index::const_mem_fun > +// boost::multi_index::ordered_non_unique< +// boost::multi_index::const_mem_fun > + > + > + indexed_modules; + std::vector relocation_table_; std::vector excpBlocks; diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index d18398ac2f..1b4251299c 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -46,7 +46,7 @@ using std::vector; #include "LineInformation.h" #include -LineInformation::LineInformation() : wasted_compares(0), num_queries(0), strings_(new StringTable) +LineInformation::LineInformation() :strings_(new StringTable), wasted_compares(0), num_queries(0) { } /* end LineInformation constructor */ @@ -104,8 +104,8 @@ bool LineInformation::getSourceLines(Offset addressInRange, vector &lines) { ++num_queries; - const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); - const_iterator end_addr_valid = impl_t::upper_bound(addressInRange + 1); + const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); + const_iterator end_addr_valid = impl_t::upper_bound(addressInRange ); while(start_addr_valid != end_addr_valid) { if(*(*start_addr_valid) == addressInRange) @@ -136,12 +136,11 @@ bool LineInformation::getSourceLines( Offset addressInRange, bool LineInformation::getAddressRanges( const char * lineSource, - unsigned int lineNo, vector< AddressRange > & ranges ) + unsigned int lineNo, vector< AddressRange > & ranges ) { auto found_statements = equal_range(lineSource, lineNo); - std::transform(found_statements.first, found_statements.second, - std::back_inserter(ranges), - std::mem_fn(&Statement::addressRange)); + std::copy(found_statements.first, found_statements.second, + std::back_inserter(ranges)); return found_statements.first != found_statements.second; } /* end getAddressRangesFromLine() */ @@ -158,9 +157,22 @@ LineInformation::const_iterator LineInformation::end() const LineInformation::const_iterator LineInformation::find(Offset addressInRange) const { ++num_queries; - const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); + const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); if(start_addr_valid == end()) return end(); - return (*start_addr_valid)->contains(addressInRange) ? start_addr_valid : end(); + const_iterator end_addr_valid = impl_t::upper_bound(addressInRange + 1); + while(start_addr_valid != end_addr_valid && start_addr_valid != end()) + { + if(*(*start_addr_valid) == addressInRange) + { + return start_addr_valid; + } + else + { + ++wasted_compares; + } + ++start_addr_valid; + } + return end(); } /* end find() */ @@ -183,12 +195,12 @@ LineInformation::~LineInformation() } LineInformation::const_line_info_iterator LineInformation::begin_by_source() const { - const traits::line_info_index& i = get(); + const traits::line_info_index& i = impl_t::get(); return i.begin(); } LineInformation::const_line_info_iterator LineInformation::end_by_source() const { - const traits::line_info_index& i = get(); + const traits::line_info_index& i = impl_t::get(); return i.end(); } @@ -198,14 +210,14 @@ LineInformation::equal_range(std::string file, const unsigned int lineNo) const unsigned index = strings_->project<0>(found) - strings_->begin(); // auto search_info = std::make_tuple(index, lineNo); std::pair bounds; - bounds = get().equal_range(index); + bounds = get().equal_range(index); while((*bounds.first)->getLine() < lineNo && bounds.first != bounds.second) { ++bounds.first; } while((*bounds.second)->getLine() > lineNo && bounds.second != bounds.first) { --bounds.second; } - if(bounds.second != get().end()) ++bounds.second; + if(bounds.second != get().end()) ++bounds.second; return bounds; // return get().equal_range(boost::cref >(search_info)); @@ -215,7 +227,7 @@ std::pairget<1>().find(file); unsigned index = strings_->project<0>(found) - strings_->begin(); - return get().equal_range(index); + return get().equal_range(index); // const traits::line_info_index& by_line_info = impl_t::get(); // return by_line_info.equal_range(file); diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 69e703d320..bd879e505d 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -197,6 +197,7 @@ LineInformation *Module::parseLineInformation() { } // Parse any CUs that have been added to our list if(!info_.empty()) { +// cout << "Parsing line info for module " << fileName() << ", have " << info_.size() << " CU DIEs to parse" << endl; for(auto cu = info_.begin(); cu != info_.end(); ++cu) @@ -497,38 +498,21 @@ void Module::finalizeRanges() ext_e = bit->second; } finalizeOneRange(ext_s, ext_e); + ranges_finalized = true; ranges.clear(); } void Module::finalizeOneRange(Address ext_s, Address ext_e) const { ModRange* r = new ModRange(ext_s, ext_e, const_cast(this)); ModRangeLookup* lookup = exec_->mod_lookup(); - std::set existing; - lookup->find(r, existing); -// cerr << "Found " << existing.size() << " overlapping intervals at insert time" << endl; - for(auto i = existing.begin(); - i != existing.end(); - ++i) - { - if((*i) && (*i)->contains(*r)) - { -// cerr << "Skipping duplicate ModRange " << r << endl; - delete r; - return; - } - if(r->contains(**i)) - { -// cerr << "Removing duplicate ModRange " << (*i) << endl; - lookup->remove(*i); - } - } - exec_->mod_lookup()->insert(r); +// cout << "Inserting range " << std::hex << (*r) << std::dec << endl; + lookup->insert(r); } -void Module::setDebugInfo(Module::DebugInfoT info) { +void Module::addDebugInfo(Module::DebugInfoT info) { +// cout << "Adding CU DIE to " << fileName() << endl; info_.push_back(info); -#if defined(cap_dwarf) -#endif + } StringTablePtr & Module::getStrings() { diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 8430717f79..3a88379c12 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -2026,10 +2026,10 @@ Symbol *Object::handle_opd_symbol(Region *opd, Symbol *sym) if (!sym) return NULL; Offset soffset = sym->getOffset(); - Offset *opd_entry = (Offset *)(((char *)opd->getPtrToRawData()) + - (soffset - opd->getDiskOffset())); assert(opd->isOffsetInRegion(soffset)); // Symbol must be in .opd section. + Offset* opd_entry = (Offset*)opd->getPtrToRawData(); + opd_entry += (soffset - opd->getDiskOffset()) / sizeof(Offset); // table of offsets; Symbol *retval = new Symbol(*sym); // Copy the .opd symbol. retval->setOffset(opd_entry[0]); // Store code address for the function. retval->setLocalTOC(opd_entry[1]); // Store TOC address for this function. @@ -2460,7 +2460,7 @@ bool Object::dwarf_parse_aranges(Dwarf_Debug dbg, std::set& dies_seen convertDebugOffset(start + len, actual_end); Module* m = associated_symtab->getOrCreateModule(modname, actual_start); m->addRange(actual_start, actual_end); - m->setDebugInfo(cu_die); + m->addDebugInfo(cu_die); DwarfWalker::buildSrcFiles(dbg, cu_die, m->getStrings()); dies_seen.insert(cu_die_off); dwarf_dealloc(dbg, ranges[i], DW_DLA_ARANGE); @@ -2514,11 +2514,12 @@ bool Object::fix_global_symbol_modules_static_dwarf() { m->addRange(r->first, r->second); } - m->setDebugInfo(cu_die); + m->addDebugInfo(cu_die); DwarfWalker::buildSrcFiles(dbg, cu_die, m->getStrings()); dies_seen.insert(cu_die_off); } + return true; } @@ -4407,14 +4408,23 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) Dyninst::Offset startAddrToUse = previousLineAddr; Dyninst::Offset endAddrToUse = lineAddr; - if (startAddrToUse && endAddrToUse && (startAddrToUse != endAddrToUse)) + if (startAddrToUse && endAddrToUse) { - // string table entry. - li_for_module->addLine((unsigned int)(previousLineSource + offset), - (unsigned int) previousLineNo, - (unsigned int) previousLineColumn, - startAddrToUse, - endAddrToUse ); + if(startAddrToUse != endAddrToUse) + { + // string table entry. + li_for_module->addLine((unsigned int)(previousLineSource + offset), + (unsigned int) previousLineNo, + (unsigned int) previousLineColumn, + startAddrToUse, + endAddrToUse ); + } +// else +// { +//// cout << dec << "Skipping entry for " << (*strings)[previousLineSource+offset] +//// << ":" << previousLineNo +//// << " at " << hex << startAddrToUse << dec << endl; +// } /* The line 'canonicalLineSource:previousLineNo' has an address range of [previousLineAddr, lineAddr). */ } diff --git a/symtabAPI/src/Symtab-edit.C b/symtabAPI/src/Symtab-edit.C index 76ca5238bc..23f2c937b7 100644 --- a/symtabAPI/src/Symtab-edit.C +++ b/symtabAPI/src/Symtab-edit.C @@ -293,16 +293,18 @@ Function *Symtab::createFunction(std::string name, } // Check to see if we contain this module... - bool found = false; - for (unsigned i = 0; i < _mods.size(); i++) { - if (_mods[i] == mod) { - found = true; - break; - } - } - if (!found) { - return NULL; - } + if(indexed_modules.get<1>().find(mod) == indexed_modules.get<1>().end()) return NULL; +// +// bool found = false; +// for (unsigned i = 0; i < indexed_modules.size(); i++) { +// if (indexed_modules[i] == mod) { +// found = true; +// break; +// } +// } +// if (!found) { +// return NULL; +// } Symbol *statSym = new Symbol(name, Symbol::ST_FUNCTION, @@ -350,14 +352,18 @@ Variable *Symtab::createVariable(std::string name, mod = getDefaultModule(); } // Check to see if we contain this module... - bool found = false; - for (unsigned i = 0; i < _mods.size(); i++) { - if (_mods[i] == mod) { - found = true; - break; - } - } - if (!found) return NULL; + if(indexed_modules.get<1>().find(mod) == indexed_modules.get<1>().end()) return NULL; +// +// bool found = false; +// for (unsigned i = 0; i < indexed_modules.size(); i++) { +// if (indexed_modules[i] == mod) { +// found = true; +// break; +// } +// } +// if (!found) { +// return NULL; +// } Symbol *statSym = new Symbol(name, Symbol::ST_OBJECT, diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 3154d45a59..6333c6757d 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -55,6 +55,9 @@ #include "symtabAPI/src/Object.h" +#include +#include + using namespace Dyninst; using namespace Dyninst::SymtabAPI; using namespace std; @@ -369,9 +372,9 @@ bool Symtab::getAllVariables(std::vector &ret) bool Symtab::getAllModules(std::vector &ret) { - if (_mods.size() >0 ) + if (indexed_modules.size() >0 ) { - ret = _mods; + std::copy(indexed_modules.begin(), indexed_modules.end(), std::back_inserter(ret)); return true; } @@ -379,36 +382,128 @@ bool Symtab::getAllModules(std::vector &ret) return false; } -bool module_less(Module* lhs, Module* rhs) -{ - if(lhs == NULL) return false; - if(rhs == NULL) return true; - return lhs->addr() < rhs->addr(); -} + bool Symtab::findModuleByOffset(Module *&ret, Offset off) { - std::set mods; - mod_lookup()->find(off, mods); - if(!mods.empty()) + + auto start_addr_valid = mod_lookup()->project( + mod_lookup()->get().lower_bound(off)); + auto end_addr_valid = mod_lookup()->upper_bound(off + 1); + Module* default_mod = getDefaultModule(); + while((start_addr_valid != end_addr_valid) && (start_addr_valid != mod_lookup_->end())) { - ret = (*mods.begin())->mod(); + if(*(*start_addr_valid) == off) + { + ret = (*start_addr_valid)->mod(); + if(ret != default_mod) return true; + } + ++start_addr_valid; } - return mods.empty(); + ret = getDefaultModule(); + return true; + +// +// auto eq = mod_lookup()->equal_range(off); +// if(eq.first != eq.second) +// { +// ret = (*(eq.first))->mod(); +// return true; +// } +// return false; +// mod_lookup()->find(off, mods); +// if(!mods.empty()) +// { +// ret = (*mods.begin())->mod(); +// } +// return mods.empty(); } +template +struct set_inserter +{ + set_inserter(std::set& t, const F& f) : m_set(t),func(f) {} + std::set& m_set; + const F& func; + template + void operator()(U elem) { + m_set.insert(func(elem)); + } +}; + +template +set_inserter make_set_inserter(std::set& t, const F& f) +{ + return set_inserter(t,f); +}; bool Symtab::findModuleByOffset(std::set&ret, Offset off) { - std::set mods; ret.clear(); - mod_lookup()->find(off, mods); - for(auto i = mods.begin(); - i != mods.end(); - ++i) +// auto mod_extractor = boost::bind(&ModRange::mod, _1); +// mod_lookup_->copy_equal_range(off, +// boost::make_function_output_iterator(make_set_inserter(ret, mod_extractor))); + auto start_addr_valid = mod_lookup()->project( + mod_lookup()->get().lower_bound(off)); + auto end_addr_valid = mod_lookup()->upper_bound(off + 1); + while(start_addr_valid != end_addr_valid && start_addr_valid != mod_lookup()->end()) { - ret.insert((*i)->mod()); + ModRange* tmp = *start_addr_valid; + if(!tmp) continue; + if(*tmp == off) + { + ret.insert(tmp->mod()); + } + ++start_addr_valid; } +// if(ret.empty()) { +// for(auto i = indexed_modules.begin(); +// i != indexed_modules.end(); +// ++i) +// { +// (void) (*i)->parseLineInformation(); +// } +// auto start_addr_valid = mod_lookup()->project( +// mod_lookup()->get().lower_bound(off)); +// auto end_addr_valid = mod_lookup()->upper_bound(off + 1); +// while(start_addr_valid != end_addr_valid && start_addr_valid != mod_lookup()->end()) +// { +// ModRange* tmp = *start_addr_valid; +// if(!tmp) continue; +// if(*tmp == off) +// { +// ret.insert(tmp->mod()); +// } +// ++start_addr_valid; +// } +//// Module::DebugInfoT info = getObject()->findDebugInfoForAddr(off); +//// auto found = indexed_modules.get<4>().find(info); +//// if(found != indexed_modules.get<4>().end()) +//// { +//// ret.insert(*found); +//// } +// } return ret.empty(); + + +// auto eq = mod_lookup()->equal_range(off); +// if(eq.first != eq.second) +// { +// std::transform(eq.first, eq.second, std::inserter(ret, ret.begin()), +// boost::bind(&ModRange::mod, _1)); +// return true; +// } +// return false; + +// std::set mods; +// ret.clear(); +// mod_lookup()->find(off, mods); +// for(auto i = mods.begin(); +// i != mods.end(); +// ++i) +// { +// ret.insert((*i)->mod()); +// } +// return ret.empty(); // // this should be a hash, really // for(int i = 0; i < _mods.size(); i++) // { @@ -424,22 +519,21 @@ bool Symtab::findModuleByOffset(std::set&ret, Offset off) bool Symtab::findModuleByName(Module *&ret, const std::string name) { - dyn_hash_map::iterator loc; - loc = modsByFullName.find(name); + auto loc = indexed_modules.get<3>().find(name); - if (loc != modsByFullName.end()) + if (loc != indexed_modules.get<3>().end()) { - ret = loc->second; + ret = *(loc); return true; } std::string tmp = extract_pathname_tail(name); - loc = modsByFileName.find(tmp); + auto loc2 = indexed_modules.get<2>().find(tmp); - if (loc != modsByFileName.end()) + if (loc2 != indexed_modules.get<2>().end()) { - ret = loc->second; + ret = *loc2; return true; } @@ -896,8 +990,8 @@ bool Symtab::getContainingInlinedFunction(Offset offset, FunctionBase* &func) } Module *Symtab::getDefaultModule() { - if(_mods.empty()) createDefaultModule(); - return _mods[0]; + if(indexed_modules.empty()) createDefaultModule(); + return indexed_modules[0]; } unsigned Function::getSize() const { diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index 4a688ccce1..eb0ef7c765 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -404,7 +404,6 @@ SYMTAB_EXPORT Symtab::Symtab(MappedFile *mf_) : // (... the rest are now initialized for everyone above ...) #endif - createDefaultModule(); } SYMTAB_EXPORT Symtab::Symtab() : @@ -441,7 +440,6 @@ SYMTAB_EXPORT Symtab::Symtab() : { init_debug_symtabAPI(); create_printf("%s[%d]: Created symtab via default constructor\n", FILE__, __LINE__); - createDefaultModule(); } SYMTAB_EXPORT bool Symtab::isExec() const @@ -725,9 +723,9 @@ bool Symtab::fixSymModules(std::vector &raw_syms) if (!obj) { return false; } - for (unsigned int i = 0; i < _mods.size(); ++i) + for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - _mods[i]->finalizeRanges(); + (*i)->finalizeRanges(); } // const std::vector > &mods = obj->modules_; @@ -1083,14 +1081,12 @@ void Symtab::setModuleLanguages(dyn_hash_map *m if (!mod_langs->size()) return; // cannot do anything here // this case will arise on non-stabs platforms until language parsing can be introduced at this level - std::vector *modlist; Module *currmod = NULL; - modlist = &_mods; //int dump = 0; - for (unsigned int i = 0; i < modlist->size(); ++i) + for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - currmod = (*modlist)[i]; + currmod = (*i); supportedLanguages currLang; if (currmod->isShared()) { continue; // need to find some way to get shared object languages? @@ -1125,14 +1121,14 @@ void Symtab::setModuleLanguages(dyn_hash_map *m } void Symtab::createDefaultModule() { - assert(_mods.empty()); + assert(indexed_modules.empty()); Module *mod = new Module(lang_Unknown, imageOffset_, name(), this); - modsByFileName[mod->fileName()] = mod; - modsByFullName[mod->fullName()] = mod; - _mods.push_back(mod); + mod->addRange(imageOffset_, imageLen_ + imageOffset_); + indexed_modules.push_back(mod); + mod->finalizeRanges(); } @@ -1140,6 +1136,9 @@ void Symtab::createDefaultModule() { Module *Symtab::getOrCreateModule(const std::string &modName, const Offset modAddr) { + if(indexed_modules.empty()) { + createDefaultModule(); + } std::string nameToUse; if (modName.length() > 0) nameToUse = modName; @@ -1197,21 +1196,19 @@ Module *Symtab::newModule(const std::string &name, const Offset addr, supportedL * different and the modules are actually different. This is an inherent * problem with how modules are processed. */ - if (modsByFileName.end() != modsByFileName.find(ret->fileName())) + if (indexed_modules.get<2>().end() != indexed_modules.get<2>().find(ret->fileName())) { create_printf("%s[%d]: WARN: LEAK? already have module with name %s\n", FILE__, __LINE__, ret->fileName().c_str()); } - if (modsByFullName.end() != modsByFullName.find(ret->fullName())) + if (indexed_modules.get<3>().end() != indexed_modules.get<3>().find(ret->fullName())) { create_printf("%s[%d]: WARN: LEAK? already have module with name %s\n", FILE__, __LINE__, ret->fullName().c_str()); } - modsByFileName[ret->fileName()] = ret; - modsByFullName[ret->fullName()] = ret; - _mods.push_back(ret); + indexed_modules.push_back(ret); return (ret); } @@ -1275,7 +1272,6 @@ Symtab::Symtab(std::string filename, bool defensive_bin, bool &err) : err = true; return; } - if (!extractInfo(obj_private)) { create_printf("%s[%d]: WARNING: creating symtab for %s, extractInfo() " @@ -1648,12 +1644,11 @@ Symtab::Symtab(const Symtab& obj) : // TODO FIXME: copying symbols/Functions/Variables // (and perhaps anything else initialized zero above) - for (i=0;ifileName()] = m; - modsByFullName[m->fullName()] = m; + Module *m = new Module(*(obj.indexed_modules[i])); + indexed_modules.push_back(m); } for (i=0; i &ranges, parseLineInformation(); /* Iteratate over the modules, looking for ranges in each. */ - for ( unsigned int i = 0; i < _mods.size(); i++ ) + for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - LineInformation *lineInformation = _mods[i]->getLineInformation(); + LineInformation *lineInformation = (*i)->getLineInformation(); if (lineInformation) lineInformation->getAddressRanges( lineSource.c_str(), lineNo, ranges ); @@ -2292,6 +2285,23 @@ SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector &ranges, SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) { unsigned int originalSize = lines.size(); + static bool did_full_parse = false; + if(!did_full_parse) + { + for(auto i = indexed_modules.begin(); + i != indexed_modules.end(); + ++i) + { + LineInformation* li = (*i)->parseLineInformation(); + } + did_full_parse = true; + for(auto j = mod_lookup()->begin(); + j != mod_lookup()->end(); + ++j) + { + cout << (**j) << endl; + } + } std::set mods_for_offset; @@ -2300,7 +2310,7 @@ SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Of i != mods_for_offset.end(); ++i) { - std::cout << "Checking module " << (*(*i)) << " for " << addressInRange << endl; +// std::cout << std::hex << "Checking module " << (*(*i)) << " for " << addressInRange << std::dec << endl; (*i)->getSourceLines(lines, addressInRange); } // /* Iteratate over the modules, looking for ranges in each. */ @@ -2404,10 +2414,10 @@ void Symtab::parseTypes() } linkedFile->parseTypeInfo(); - for (unsigned int i = 0; i < _mods.size(); ++i) + for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - _mods[i]->setModuleTypes(typeCollection::getModTypeCollection(_mods[i])); - _mods[i]->finalizeRanges(); + (*i)->setModuleTypes(typeCollection::getModTypeCollection((*i))); + (*i)->finalizeRanges(); } // optionally we might want to clear the static data struct in typeCollection @@ -2441,12 +2451,12 @@ SYMTAB_EXPORT bool Symtab::findType(Type *&type, std::string name) { parseTypesNow(); - if (!_mods.size()) + if (indexed_modules.empty()) return false; - for (unsigned int i = 0; i < _mods.size(); ++i) + for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - typeCollection *tc = _mods[i]->getModuleTypes(); + typeCollection *tc = (*i)->getModuleTypes(); if (!tc) continue; type = tc->findType(name); if (type) return true; @@ -2463,14 +2473,14 @@ SYMTAB_EXPORT Type *Symtab::findType(unsigned type_id) Type *t = NULL; parseTypesNow(); - if (!_mods.size()) + if (indexed_modules.empty()) { return NULL; } - for (unsigned int i = 0; i < _mods.size(); ++i) + for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - typeCollection *tc = _mods[i]->getModuleTypes(); + typeCollection *tc = (*i)->getModuleTypes(); if (!tc) continue; t = tc->findType(type_id); if (t) break; @@ -2499,14 +2509,10 @@ SYMTAB_EXPORT Type *Symtab::findType(unsigned type_id) SYMTAB_EXPORT bool Symtab::findVariableType(Type *&type, std::string name) { parseTypesNow(); - - if (!_mods.size()) - return false; - - - for (unsigned int i = 0; i < _mods.size(); ++i) + type = NULL; + for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - typeCollection *tc = _mods[i]->getModuleTypes(); + typeCollection *tc = (*i)->getModuleTypes(); if (!tc) continue; type = tc->findVariableType(name); if (type) break; @@ -2890,7 +2896,7 @@ SYMTAB_EXPORT std::string Symtab::file() const SYMTAB_EXPORT std::string Symtab::name() const { - return obj_private->getFileName(); + return mf->filename(); } SYMTAB_EXPORT std::string Symtab::memberName() const @@ -2908,179 +2914,6 @@ SYMTAB_EXPORT unsigned Symtab::getNumberOfSymbols() const return no_of_symbols; } -bool Symtab::setup_module_up_ptrs(SerializerBase *, Symtab *st) -{ - std::vector &mods = st->_mods; - - for (unsigned int i = 0; i < mods.size(); ++i) - { - Module *m = mods[i]; - m->exec_ = st; - } - - return true; -} - -bool Symtab::fixup_relocation_symbols(SerializerBase *, Symtab *st) -{ - std::vector &mods = st->_mods; - - for (unsigned int i = 0; i < mods.size(); ++i) - { - Module *m = mods[i]; - m->exec_ = st; - } - - return true; -} - -void Symtab::rebuild_symbol_hashes(SerializerBase * /*sb*/) -{ - /* if (!is_input(sb)) - return; - - for (unsigned long i = 0; i < everyDefinedSymbol.size(); ++i) - { - Symbol *s = everyDefinedSymbol[i]; - assert(s); - const std::string &pn = s->getPrettyName(); - const std::string &mn = s->getMangledName(); - const std::string tn = s->getTypedName(); - - symsByPrettyName[pn].push_back(s); - symsByMangledName[mn].push_back(s); - symsByTypedName[tn].push_back(s); - symsByOffset[s->getOffset()].push_back(s); - } - */ -} - -void Symtab::rebuild_funcvar_hashes(SerializerBase *sb) -{ - if (!is_input(sb)) - return; - for (unsigned int i = 0; i < everyFunction.size(); ++i) - { - Function *f = everyFunction[i]; - funcsByOffset[f->getOffset()] = f; - } - for (unsigned int i = 0; i < everyVariable.size(); ++i) - { - Variable *v = everyVariable[i]; - varsByOffset[v->getOffset()] = v; - } -} -void Symtab::rebuild_module_hashes(SerializerBase *sb) -{ - if (!is_input(sb)) - return; - for (unsigned int i = 0; i < _mods.size(); ++i) - { - Module *m = _mods[i]; - modsByFileName[m->fileName()] = m; - modsByFullName[m->fullName()] = m; - } -} -void Symtab::rebuild_region_indexes(SerializerBase *sb) THROW_SPEC (SerializerError) -{ - if (!is_input(sb)) - return; - - for (unsigned int i = 0; i < regions_.size(); ++i) - { - Region *r = regions_[i]; - - if ( r->isLoadable() ) - { - if ((r->getRegionPermissions() == Region::RP_RX) - || (r->getRegionPermissions() == Region::RP_RWX)) - codeRegions_.push_back(r); - else - dataRegions_.push_back(r); - } - - // entry addr might require some special attn on windows, since it - // is not the disk offset but the actual mem addr, which is going to be - // different after deserialize. Probably have to look it up again. - regionsByEntryAddr[r->getMemOffset()] = r; - } - - std::sort(codeRegions_.begin(), codeRegions_.end(), sort_reg_by_addr); - std::sort(dataRegions_.begin(), dataRegions_.end(), sort_reg_by_addr); -} - -#if !defined(SERIALIZATION_DISABLED) -Serializable *Symtab::serialize_impl(SerializerBase *sb, - const char *tag) THROW_SPEC (SerializerError) -{ - serialize_printf("%s[%d]: welcome to Symtab::serialize_impl\n", - FILE__, __LINE__); - if (is_input(sb)) - { - // don't bother with serializing standard and builtin types. - /* XXX Change to use safe static allocation and initialization - of standard and builtin types changes serialization behavior: - these types are initialized on first access to the types - structures (no explicit initialization). I think this code - is dead anyway, though, so it probably doesn't matter. - */ - //setupTypes(); - } - - ifxml_start_element(sb, tag); - gtranslate(sb, imageOffset_, "imageOffset"); - gtranslate(sb, imageLen_, "imageLen"); - gtranslate(sb, dataOffset_, "dataOff"); - gtranslate(sb, dataLen_, "dataLen"); - gtranslate(sb, is_a_out, "isExec"); - gtranslate(sb, _mods, "Modules", "Module"); - rebuild_module_hashes(sb); - if (is_input(sb)) - { - // problem: if isTypeInfoValid_ is not true, we can trigger type parsing - // for an object class that does not exist. Need to introduce logic to - // recreate the object in this case - isTypeInfoValid_ = true; - } - gtranslate(sb, regions_, "Regions", "Region"); - rebuild_region_indexes(sb); - gtranslate(sb, everyDefinedSymbol, "EveryDefinedSymbol", "Symbol"); - rebuild_symbol_hashes(sb); - gtranslate(sb, relocation_table_, "RelocationTable", "RelocationTableEntry"); - gtranslate(sb, everyFunction, "EveryFunction", "Function"); - gtranslate(sb, everyVariable, "EveryVariable", "Variable"); - rebuild_funcvar_hashes(sb); - - //gtranslate(sb, everyUniqueVariable, "EveryUniqueVariable", "UniqueVariable"); - //gtranslate(sb, modSyms, "ModuleSymbols", "ModuleSymbol"); - - gtranslate(sb, excpBlocks, "ExceptionBlocks", "ExceptionBlock"); - ifxml_end_element(sb, tag); - - sb->magic_check(FILE__, __LINE__); -#if 0 - ifinput(Symtab::setup_module_up_ptrs, sb, this); - ifinput(fixup_relocation_symbols, sb, this); -#endif - - if (is_input(sb)) - { - dyn_hash_map *map_p = NULL; - if (getAnnotation(map_p, IdToSymAnno) && (NULL != map_p)) - { - removeAnnotation(IdToSymAnno); - delete map_p; - } - } - serialize_printf("%s[%d]: leaving Symtab::serialize_impl\n", FILE__, __LINE__); - return NULL; -} -#else -Serializable *Symtab::serialize_impl(SerializerBase *, const char *) THROW_SPEC (SerializerError) -{ - return NULL; -} -#endif SYMTAB_EXPORT LookupInterface::LookupInterface() { From 7d486e744f48edd95b5b94b19e916ab0d0cd553a Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 10 Oct 2016 11:58:13 -0500 Subject: [PATCH 138/180] Cleanup --- symtabAPI/h/RangeLookup.h | 5 +++++ symtabAPI/src/Symtab.C | 6 ------ symtabAPI/src/dwarfWalker.C | 7 ++----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index a103aa9f16..6e113764e8 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -91,6 +91,11 @@ namespace Dyninst { } }; + inline std::ostream& operator<<(std::ostream& os, AddressRange ar) + { + os << std::hex << "[" << ar.first << ", " << ar.second << ")"; + return os; + } template struct RangeLookupTypes { diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index eb0ef7c765..d379f2ebaf 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -2295,12 +2295,6 @@ SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Of LineInformation* li = (*i)->parseLineInformation(); } did_full_parse = true; - for(auto j = mod_lookup()->begin(); - j != mod_lookup()->end(); - ++j) - { - cout << (**j) << endl; - } } diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index de0e9caea0..d1ed5a294f 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -677,7 +677,7 @@ pair DwarfWalker::parseHighPCLowPC(Dwarf_Debug dbg, Dwarf_Di if (!findConstant(DW_AT_low_pc, low, entry, dbg)) return result; if (!findConstant(DW_AT_high_pc, high, entry, dbg)) return result; Dwarf_Half form; - DWARF_FAIL_RET(dwarf_whatform(hasHigh, &form, NULL)); + if(dwarf_whatform(hasHigh, &form, NULL) != DW_DLV_OK) return result; if(form != DW_FORM_addr) { @@ -738,8 +738,6 @@ vector DwarfWalker::getDieRanges(Dwarf_Debug dbg, Dwarf_Die die, O } dwarf_ranges_dealloc(dbg, ranges, ranges_length); } - - } return newRanges; } @@ -1298,8 +1296,7 @@ bool DwarfWalker::parseTypeReferences() { return false; } - assert( indirectType != NULL ); - } + assert( indirectType != NULL ); return true; } From 861e5d54ab1bfe34605dc937d05dcbe63f40e554 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 13 Oct 2016 11:59:40 -0500 Subject: [PATCH 139/180] Interval refactoring. --- common/h/IBSTree.h | 41 ++++------ parseAPI/h/CFG.h | 7 +- parseAPI/h/CodeSource.h | 2 +- symtabAPI/h/Module.h | 47 ++++-------- symtabAPI/h/Symtab.h | 3 +- symtabAPI/src/LineInformation.C | 3 +- symtabAPI/src/Object-elf.C | 27 +++++-- symtabAPI/src/Symtab-lookup.C | 130 +++----------------------------- 8 files changed, 69 insertions(+), 191 deletions(-) diff --git a/common/h/IBSTree.h b/common/h/IBSTree.h index 779e64e12d..9a4b0a5878 100644 --- a/common/h/IBSTree.h +++ b/common/h/IBSTree.h @@ -82,44 +82,33 @@ namespace IBS { typedef enum { TREE_RED, TREE_BLACK } color_t; }; -template -class interval { - public: - interval() { } - virtual ~interval() { } - - virtual T low() const = 0; - virtual T high() const = 0; - - typedef T type; -}; -class SimpleInterval : public interval { +template +class SimpleInterval +{ public: - SimpleInterval( interval & i, void * id ) { - low_ = i.low(); - high_ = i.high(); - id_ = id; - } - SimpleInterval(int low, int high, void * id) { + typedef T type; + SimpleInterval(T low, T high, U id) { low_ = low; high_ = high; id_ = id; } + SimpleInterval() {} + virtual ~SimpleInterval() {} - virtual int low() const { return low_; } - virtual int high() const { return high_; } - + virtual T low() const { return low_; } + virtual T high() const { return high_; } + virtual U id() const { return id_; } protected: - int low_; - int high_; - void * id_; // some arbitrary unique identifier + T low_; + T high_; + U id_; // some arbitrary unique identifier }; template class IBSTree; -template > +template > class IBSNode { friend class IBSTree; typedef typename ITYPE::type interval_type; @@ -160,7 +149,7 @@ class IBSNode { IBSNode *parent; }; -template > +template > class IBSTree { public: typedef typename ITYPE::type interval_type; diff --git a/parseAPI/h/CFG.h b/parseAPI/h/CFG.h index 7d37e47445..fa149e9537 100644 --- a/parseAPI/h/CFG.h +++ b/parseAPI/h/CFG.h @@ -284,7 +284,7 @@ class Function; }; class CodeRegion; -class PARSER_EXPORT Block : public Dyninst::interval
, +class PARSER_EXPORT Block : public Dyninst::SimpleInterval, public allocatable { friend class CFGModifier; public: @@ -655,7 +655,7 @@ class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse { }; /* Describes a contiguous extent of a Function object */ -class PARSER_EXPORT FuncExtent : public Dyninst::interval
{ +class PARSER_EXPORT FuncExtent : public Dyninst::SimpleInterval { private: Function * _func; Address _start; @@ -667,7 +667,7 @@ class PARSER_EXPORT FuncExtent : public Dyninst::interval
{ _start(start), _end(end) { } - ~FuncExtent() { + virtual ~FuncExtent() { _func = NULL; } @@ -679,6 +679,7 @@ class PARSER_EXPORT FuncExtent : public Dyninst::interval
{ /* interval implementation */ Address low() const { return _start; } Address high() const { return _end; } + Function* id() const { return _func; } bool operator==(const FuncExtent &rhs) const { return _func == rhs._func && diff --git a/parseAPI/h/CodeSource.h b/parseAPI/h/CodeSource.h index 383325f2c6..2f7690acc5 100644 --- a/parseAPI/h/CodeSource.h +++ b/parseAPI/h/CodeSource.h @@ -54,7 +54,7 @@ class CFGModifier; **/ -class PARSER_EXPORT CodeRegion : public Dyninst::InstructionSource, public Dyninst::interval
{ +class PARSER_EXPORT CodeRegion : public Dyninst::InstructionSource, public Dyninst::SimpleInterval
{ public: /* Fills a vector with any names associated with the function at at diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 056a8048da..9d64a2e71a 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -116,14 +116,14 @@ class SYMTAB_EXPORT Statement : public AddressRange template OS& operator<<(OS& os, const Statement& s) { - os << ": [" << s.startAddr() << ", " << s.endAddr() << ") @ " << s.getFile() + os << ": [" << std::hex << s.startAddr() << ", " << s.endAddr() << std::dec << ") @ " << s.getFile() << " (" << s.getFileIndex() << "): " << s.getLine(); return os; } template OS& operator<<(OS& os, Statement* s) { - os << ": [" << s->startAddr() << ", " << s->endAddr() << ") @ " << s->getFile() + os << ": [" << std::hex << s->startAddr() << ", " << s->endAddr() << std::dec << ") @ " << s->getFile() << " (" << s->getFileIndex() << "): " << s->getLine(); return os; } @@ -267,39 +267,20 @@ typedef Statement LineNoTuple; return os; } +typedef Dyninst::SimpleInterval ModRange; -struct ModRange : public Dyninst::Interval +inline bool operator==(Offset off, const ModRange& r) { + return (r.low() <= off) && (off < r.high()); +} +inline bool operator==(const ModRange& r, Offset off) { + return off == r; +} +template +OS& operator<<(OS& os, const ModRange& m) { - typedef Dyninst::Interval parent; - ModRange(Offset l, Offset h, Module* m) : - Dyninst::Interval(l, h), mod_(m) - {} - - bool operator==(const ModRange &rhs) const { - return (parent::operator==(rhs)) && (mod_ == rhs.mod_); - } - - bool operator!=(const ModRange &rhs) const { - return !(rhs == *this); - } - bool contains(const ModRange& rhs) const { - return (rhs.first >= first) && - (rhs.second <= second) && - (rhs.mod() == mod()); - } - bool operator==(Offset off) const { - return parent::operator==(off); - } - Module* mod() const { return mod_;} - Module* mod_; - typedef ModRange* Ptr; -}; - template - OS& operator<<(OS& os, const ModRange& m) - { - os << m.mod() << ": [" << m.first << ", " << m.second << ")"; - return os; - } + os << m.id() << ": [" << m.low << ", " << m.high << ")"; + return os; +} }//namespace SymtabAPI diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index 35c973d135..c30eb8cc84 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -85,9 +85,8 @@ class relocationEntry; class Type; class FunctionBase; class FuncRange; -class ModRange; -typedef IntervalLookup< ModRange > ModRangeLookup; +typedef IBSTree< ModRange > ModRangeLookup; typedef IBSTree FuncRangeLookup; typedef Dyninst::ProcessReader MemRegReader; diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 1b4251299c..9014d613d6 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -104,7 +104,8 @@ bool LineInformation::getSourceLines(Offset addressInRange, vector &lines) { ++num_queries; - const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); +// const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); + const_iterator start_addr_valid = impl_t::lower_bound(std::make_tuple(0, addressInRange)); const_iterator end_addr_valid = impl_t::upper_bound(addressInRange ); while(start_addr_valid != end_addr_valid) { diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 3a88379c12..0c787a5c03 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -4392,6 +4392,12 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) if ( status != DW_DLV_OK ) { continue; } + Dwarf_Bool isStatement; + status = dwarf_linebeginstatement(lineBuffer[i], &isStatement, NULL); + if(status != DW_DLV_OK) { + continue; + } + if ( isPreviousValid ) { /* If we're talking about the same (source file, line number) tuple, @@ -4410,6 +4416,12 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) if (startAddrToUse && endAddrToUse) { + if(startAddrToUse == (Dyninst::Offset)(-1) || endAddrToUse == (Dyninst::Offset)(-1)) { + cout << "Suspicious line info range: [" << hex << startAddrToUse << ", " << endAddrToUse << ")\n"; + } + if(startAddrToUse == (Dyninst::Offset)(1) || endAddrToUse == (Dyninst::Offset)(1)) { + cout << "Suspicious line info range: [" << hex << startAddrToUse << ", " << endAddrToUse << ")\n"; + } if(startAddrToUse != endAddrToUse) { // string table entry. @@ -4435,15 +4447,18 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) // only one has an end marker. Carry through in that case. if ( isEndOfSequence ) { - isPreviousValid = (lineAddr == previousLineAddr) ; + isPreviousValid = false; //(lineAddr == previousLineAddr) ; } else { - previousLineNo = lineNo; - previousLineSource = lineSource; - previousLineAddr = lineAddr; - previousLineColumn = lineOff; + if(isStatement) + { + isPreviousValid = true; //((previousLineNo != lineNo) && (previousLineSource != lineSource)); + previousLineNo = lineNo; + previousLineSource = lineSource; + previousLineAddr = lineAddr; + previousLineColumn = lineOff; + } - isPreviousValid = true; } /* end if line was not the end of a sequence */ } /* end iteration over source line entries. */ diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 6333c6757d..1625939c41 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -386,135 +386,27 @@ bool Symtab::getAllModules(std::vector &ret) bool Symtab::findModuleByOffset(Module *&ret, Offset off) { - auto start_addr_valid = mod_lookup()->project( - mod_lookup()->get().lower_bound(off)); - auto end_addr_valid = mod_lookup()->upper_bound(off + 1); - Module* default_mod = getDefaultModule(); - while((start_addr_valid != end_addr_valid) && (start_addr_valid != mod_lookup_->end())) + std::set mods; + mod_lookup()->find(off, mods); + if(!mods.empty()) { - if(*(*start_addr_valid) == off) - { - ret = (*start_addr_valid)->mod(); - if(ret != default_mod) return true; - } - ++start_addr_valid; + ret = (*mods.begin())->id(); } - ret = getDefaultModule(); - return true; - -// -// auto eq = mod_lookup()->equal_range(off); -// if(eq.first != eq.second) -// { -// ret = (*(eq.first))->mod(); -// return true; -// } -// return false; -// mod_lookup()->find(off, mods); -// if(!mods.empty()) -// { -// ret = (*mods.begin())->mod(); -// } -// return mods.empty(); + return mods.empty(); } -template -struct set_inserter -{ - set_inserter(std::set& t, const F& f) : m_set(t),func(f) {} - std::set& m_set; - const F& func; - template - void operator()(U elem) { - m_set.insert(func(elem)); - } -}; - -template -set_inserter make_set_inserter(std::set& t, const F& f) -{ - return set_inserter(t,f); -}; - bool Symtab::findModuleByOffset(std::set&ret, Offset off) { + std::set mods; ret.clear(); -// auto mod_extractor = boost::bind(&ModRange::mod, _1); -// mod_lookup_->copy_equal_range(off, -// boost::make_function_output_iterator(make_set_inserter(ret, mod_extractor))); - auto start_addr_valid = mod_lookup()->project( - mod_lookup()->get().lower_bound(off)); - auto end_addr_valid = mod_lookup()->upper_bound(off + 1); - while(start_addr_valid != end_addr_valid && start_addr_valid != mod_lookup()->end()) + mod_lookup()->find(off, mods); + for(auto i = mods.begin(); + i != mods.end(); + ++i) { - ModRange* tmp = *start_addr_valid; - if(!tmp) continue; - if(*tmp == off) - { - ret.insert(tmp->mod()); - } - ++start_addr_valid; + ret.insert((*i)->id()); } -// if(ret.empty()) { -// for(auto i = indexed_modules.begin(); -// i != indexed_modules.end(); -// ++i) -// { -// (void) (*i)->parseLineInformation(); -// } -// auto start_addr_valid = mod_lookup()->project( -// mod_lookup()->get().lower_bound(off)); -// auto end_addr_valid = mod_lookup()->upper_bound(off + 1); -// while(start_addr_valid != end_addr_valid && start_addr_valid != mod_lookup()->end()) -// { -// ModRange* tmp = *start_addr_valid; -// if(!tmp) continue; -// if(*tmp == off) -// { -// ret.insert(tmp->mod()); -// } -// ++start_addr_valid; -// } -//// Module::DebugInfoT info = getObject()->findDebugInfoForAddr(off); -//// auto found = indexed_modules.get<4>().find(info); -//// if(found != indexed_modules.get<4>().end()) -//// { -//// ret.insert(*found); -//// } -// } return ret.empty(); - - -// auto eq = mod_lookup()->equal_range(off); -// if(eq.first != eq.second) -// { -// std::transform(eq.first, eq.second, std::inserter(ret, ret.begin()), -// boost::bind(&ModRange::mod, _1)); -// return true; -// } -// return false; - -// std::set mods; -// ret.clear(); -// mod_lookup()->find(off, mods); -// for(auto i = mods.begin(); -// i != mods.end(); -// ++i) -// { -// ret.insert((*i)->mod()); -// } -// return ret.empty(); -// // this should be a hash, really -// for(int i = 0; i < _mods.size(); i++) -// { -// if(_mods[i]->containsOffset(off)) -// { -// ret = _mods[i]; -// return true; -// } -// } -// ret = NULL; -// return false; } bool Symtab::findModuleByName(Module *&ret, const std::string name) From 74d5bea71e17116559870653620de7cb3775b0c3 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 19 Oct 2016 15:10:23 -0500 Subject: [PATCH 140/180] Code cleanup: we don't need to handle the cases where there's no module range info. --- elf/src/Elf_X.C | 18 ---------------- symtabAPI/src/LineInformation.C | 3 +-- symtabAPI/src/Module.C | 8 ------- symtabAPI/src/Symtab.C | 37 ++++++--------------------------- 4 files changed, 7 insertions(+), 59 deletions(-) diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index 75790ebeba..260ce42d2e 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -856,24 +856,6 @@ size_t Elf_X_Data::d_align() const { return data->d_align; } -void Elf_X_Data::xlatetom(unsigned int encode) -{ - if(is64) - { - elf64_xlatetom(data, data, encode); - } else { - elf32_xlatetom(data, data, encode); - } -} -void Elf_X_Data::xlatetof(unsigned int encode) -{ - if(is64) - { - elf64_xlatetof(data, data, encode); - } else { - elf32_xlatetof(data, data, encode); - } -} // Write Interface void Elf_X_Data::d_buf(void *input) diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 9014d613d6..1b4251299c 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -104,8 +104,7 @@ bool LineInformation::getSourceLines(Offset addressInRange, vector &lines) { ++num_queries; -// const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); - const_iterator start_addr_valid = impl_t::lower_bound(std::make_tuple(0, addressInRange)); + const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); const_iterator end_addr_valid = impl_t::upper_bound(addressInRange ); while(start_addr_valid != end_addr_valid) { diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index bd879e505d..8d3b7530ec 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -188,7 +188,6 @@ bool Module::getSourceLines(std::vector &lines, Offset addressInRan LineInformation *Module::parseLineInformation() { // Allocate if none - using boost::bind; if (!lineInfo_) { lineInfo_ = new LineInformation; @@ -197,19 +196,12 @@ LineInformation *Module::parseLineInformation() { } // Parse any CUs that have been added to our list if(!info_.empty()) { -// cout << "Parsing line info for module " << fileName() << ", have " << info_.size() << " CU DIEs to parse" << endl; for(auto cu = info_.begin(); cu != info_.end(); ++cu) { exec()->getObject()->parseLineInfoForCU(*cu, lineInfo_); } - // Add ranges corresponding to each statement - std::for_each(lineInfo_->begin(), lineInfo_->end(), - boost::bind(&Module::addRange, this, boost::bind(&Statement::startAddr, _1), boost::bind(&Statement::endAddr, _1))); - - // Update in symtab: this module covers all ranges in its line info - finalizeRanges(); } // Clear list of work to do info_.clear(); diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index d379f2ebaf..b17870a327 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -2269,10 +2269,12 @@ SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector &ranges, /* Iteratate over the modules, looking for ranges in each. */ for (auto i = indexed_modules.begin(); i != indexed_modules.end(); ++i) { - LineInformation *lineInformation = (*i)->getLineInformation(); - - if (lineInformation) - lineInformation->getAddressRanges( lineSource.c_str(), lineNo, ranges ); + StringTablePtr s = (*i)->getStrings(); + // Only check modules that have this filename present + if(s->get<1>().find(lineSource) == s->get<1>().end()) continue; + LineInformation *lineInformation = (*i)->parseLineInformation(); + if (lineInformation) + lineInformation->getAddressRanges( lineSource.c_str(), lineNo, ranges ); } /* end iteration over modules */ @@ -2285,45 +2287,18 @@ SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector &ranges, SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector &lines, Offset addressInRange) { unsigned int originalSize = lines.size(); - static bool did_full_parse = false; - if(!did_full_parse) - { - for(auto i = indexed_modules.begin(); - i != indexed_modules.end(); - ++i) - { - LineInformation* li = (*i)->parseLineInformation(); - } - did_full_parse = true; - } - - std::set mods_for_offset; findModuleByOffset(mods_for_offset, addressInRange); for(auto i = mods_for_offset.begin(); i != mods_for_offset.end(); ++i) { -// std::cout << std::hex << "Checking module " << (*(*i)) << " for " << addressInRange << std::dec << endl; (*i)->getSourceLines(lines, addressInRange); } -// /* Iteratate over the modules, looking for ranges in each. */ -// for ( unsigned int i = 0; i < _mods.size(); i++ ) -// { -// LineInformation *lineInformation = _mods[i]->getLineInformation(); -// -// if (lineInformation) -// lineInformation->getSourceLines( addressInRange, lines ); -// -// } /* end iteration over modules */ if ( lines.size() != originalSize ) return true; - if(!mods_for_offset.empty()) { - std::cout << "WARNING: Modules have ranges for 0x" << std::hex << addressInRange << " but lack line info"<< std::endl; - std::copy(mods_for_offset.begin(), mods_for_offset.end(), std::ostream_iterator(std::cout, "\n")); - } return false; } From b7a18a1fce2c513fb3d06b12221690db72310879 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 19 Oct 2016 15:55:04 -0500 Subject: [PATCH 141/180] Name fix for Windows --- symtabAPI/src/Object-nt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symtabAPI/src/Object-nt.h b/symtabAPI/src/Object-nt.h index 41f5489e27..a110f1e108 100644 --- a/symtabAPI/src/Object-nt.h +++ b/symtabAPI/src/Object-nt.h @@ -240,7 +240,7 @@ class Object : public AObject SYMTAB_EXPORT void parseFileLineInfo(); SYMTAB_EXPORT void parseLineInfoForAddr(Offset) { - parseFileLineInfo(associatedSymtab); + parseFileLineInfo(associated_symtab); } SYMTAB_EXPORT void FindInterestingSections( bool, bool ); From 2ace8828d593831a4cbebfbed8e93cfc0c1210d2 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 19 Oct 2016 16:13:57 -0500 Subject: [PATCH 142/180] More Windows cleanup --- symtabAPI/src/Object-nt.C | 4 ++-- symtabAPI/src/Object-nt.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index ba77052480..59fd02ddf1 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -1116,8 +1116,8 @@ void fixup_filename(std::string &filename) Object::Object(MappedFile *mf_, bool defensive, - void (*err_func)(const char *), bool alloc_syms) : - AObject(mf_, err_func), + void (*err_func)(const char *), bool alloc_syms, Symtab *st) : + AObject(mf_, err_func, st), curModule( NULL ), baseAddr( 0 ), imageBase( 0 ), diff --git a/symtabAPI/src/Object-nt.h b/symtabAPI/src/Object-nt.h index a110f1e108..9da7effe17 100644 --- a/symtabAPI/src/Object-nt.h +++ b/symtabAPI/src/Object-nt.h @@ -176,7 +176,7 @@ class Object : public AObject public: SYMTAB_EXPORT Object(MappedFile *, bool defensive, - void (*)(const char *) = log_msg, bool alloc_syms = true, Symtab*); + void (*)(const char *) = log_msg, bool alloc_syms = true, Symtab* st = NULL); SYMTAB_EXPORT virtual ~Object( void ); SYMTAB_EXPORT std::string getFileName() const { return mf->filename(); } @@ -240,7 +240,7 @@ class Object : public AObject SYMTAB_EXPORT void parseFileLineInfo(); SYMTAB_EXPORT void parseLineInfoForAddr(Offset) { - parseFileLineInfo(associated_symtab); + parseFileLineInfo(); } SYMTAB_EXPORT void FindInterestingSections( bool, bool ); From 4cffc883c919b443c47abbc7f1dffea302323409 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 19 Oct 2016 16:39:23 -0500 Subject: [PATCH 143/180] Stream out module low/high addresses, not function pointers (which breaks clang, in addition to being wrong). --- symtabAPI/h/Module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 9d64a2e71a..de55990ebb 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -278,7 +278,7 @@ inline bool operator==(const ModRange& r, Offset off) { template OS& operator<<(OS& os, const ModRange& m) { - os << m.id() << ": [" << m.low << ", " << m.high << ")"; + os << m.id() << ": [" << m.low() << ", " << m.high() << ")"; return os; } From e0bff3419fd4fa928be43918388a3fc3e71ba9df Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 20 Oct 2016 11:18:27 -0500 Subject: [PATCH 144/180] Disable boost's variadic templates under MSVC, as they're known buggy on some versions. --- cmake/shared.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index d3df0cd60a..d0df3d09c2 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -106,7 +106,7 @@ IF(CMAKE_COMPILER_IS_GNUCC) ENDIF(CMAKE_COMPILER_IS_GNUCC) # If we're compiling for unix, cotire only supports Intel, GCC and Clang. -IF (UNIX AND NOT (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel"))) +IF (UNIX AND NOT ((${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel"))) set(USE_COTIRE false) ENDIF() @@ -168,3 +168,9 @@ if (NOT CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the build type (None, Debug, Release, RelWithDebInfo, MinSizeRel)" FORCE) endif() + +# There are broken versions of MSVC that won't handle variadic templates correctly (despite the C++11 test case passing). +# Just build vanilla versions, boost can handle it. +if (MSVC) + add_definitions(-DBOOST_NO_CXX11_VARIADIC_TEMPLATES) +endif() \ No newline at end of file From 181881c75d4b0f6c4a4ac34f7b9ad0802c80b5d4 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 20 Oct 2016 11:21:34 -0500 Subject: [PATCH 145/180] Cleanup --- cmake/shared.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index d0df3d09c2..0a8131c456 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -106,7 +106,7 @@ IF(CMAKE_COMPILER_IS_GNUCC) ENDIF(CMAKE_COMPILER_IS_GNUCC) # If we're compiling for unix, cotire only supports Intel, GCC and Clang. -IF (UNIX AND NOT ((${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel"))) +IF (UNIX AND NOT ((${CMAKE_CXX_COMPILER_ID} MATCHES Clang) OR (${CMAKE_CXX_COMPILER_ID} MATCHES GNU) OR (${CMAKE_CXX_COMPILER_ID} MATCHES Intel))) set(USE_COTIRE false) ENDIF() From 413e1a176913f68509787109755d2485527d395e Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 20 Oct 2016 16:42:06 -0500 Subject: [PATCH 146/180] Make parseLineInfoForCU accessible (though it's not used for PE files at present) --- symtabAPI/src/Object.h | 1 + 1 file changed, 1 insertion(+) diff --git a/symtabAPI/src/Object.h b/symtabAPI/src/Object.h index 8dacfa10e0..c4cf5a9350 100644 --- a/symtabAPI/src/Object.h +++ b/symtabAPI/src/Object.h @@ -148,6 +148,7 @@ class AObject { SYMTAB_EXPORT virtual ~AObject(); // explicitly protected SYMTAB_EXPORT AObject(MappedFile *, void (*err_func)(const char *), Symtab*); +friend class Module; virtual void parseLineInfoForCU(Module::DebugInfoT , LineInformation* ) { } MappedFile *mf; From 9430ba950a271a3b8af39a490c668acba1b1913a Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 24 Oct 2016 13:06:50 -0500 Subject: [PATCH 147/180] Implement symreader dependency on Windows --- symtabAPI/src/Object-nt.C | 16 ++++++++++++++++ symtabAPI/src/Object-nt.h | 1 + 2 files changed, 17 insertions(+) diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index 59fd02ddf1..d5fd138408 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -2218,6 +2218,22 @@ bool AObject::getSegments(vector &segs) const return true; } +void Object::getSegmentsSymReader(std::vector & sym_segs) +{ + for(auto i = regions_.begin(); + i != regions_.end(); + ++i) + { + SymSegment s; + s.file_offset = (*i)->getDiskOffset(); + s.file_size = (*i)->getDiskSize(); + s.mem_addr = (*i)->getMemOffset(); + s.mem_size = (*i)->getMemSize(); + s.perms = (*i)->getRegionPermissions(); + s.type = (*i)->getRegionType(); + } +} + bool Object::emitDriver(string fName, std::vector &allSymbols, unsigned flag) { emitWin *em = new emitWin((PCHAR)GetMapAddr(), this, err_func_); diff --git a/symtabAPI/src/Object-nt.h b/symtabAPI/src/Object-nt.h index 9da7effe17..09b706db4d 100644 --- a/symtabAPI/src/Object-nt.h +++ b/symtabAPI/src/Object-nt.h @@ -234,6 +234,7 @@ class Object : public AObject SYMTAB_EXPORT void rebase(Offset off); SYMTAB_EXPORT Region* findRegionByName(const std::string& name) const; SYMTAB_EXPORT void applyRelocs(Region* relocs, Offset delta); + SYMTAB_EXPORT virtual void getSegmentsSymReader(std::vector &); private: SYMTAB_EXPORT void ParseSymbolInfo( bool ); From bcb65b6dcaa541ddb6efc57fc931f80267ddbaf8 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 24 Oct 2016 16:49:13 -0500 Subject: [PATCH 148/180] Remove IDE files from repo --- .idea/deployment.xml | 11 ++++++++++- dataflowAPI/src/stackanalysis.C | 8 ++++---- dyninstAPI/src/BPatch_type.C | 8 ++++---- dyninstAPI/src/function.C | 8 ++++---- dyninstAPI/src/image.C | 4 ++-- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.idea/deployment.xml b/.idea/deployment.xml index fb268c190c..82e0b3b01a 100644 --- a/.idea/deployment.xml +++ b/.idea/deployment.xml @@ -5,7 +5,16 @@ - + + + + + + + + + + diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index 2c54c61474..98e52d4bcd 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -61,13 +61,13 @@ const StackAnalysis::Height StackAnalysis::Height::top( StackAnalysis::Height::uninitialized, StackAnalysis::Height::TOP); AnnotationClass - Stack_Anno_Intervals(std::string("Stack_Anno_Intervals")); + Stack_Anno_Intervals(std::string("Stack_Anno_Intervals"), nullptr); AnnotationClass - Stack_Anno_Block_Effects(std::string("Stack_Anno_Block_Effects")); + Stack_Anno_Block_Effects(std::string("Stack_Anno_Block_Effects"), nullptr); AnnotationClass - Stack_Anno_Insn_Effects(std::string("Stack_Anno_Insn_Effects")); + Stack_Anno_Insn_Effects(std::string("Stack_Anno_Insn_Effects"), nullptr); AnnotationClass - Stack_Anno_Call_Effects(std::string("Stack_Anno_Call_Effects")); + Stack_Anno_Call_Effects(std::string("Stack_Anno_Call_Effects"), nullptr); template class std::list; template class std::map; diff --git a/dyninstAPI/src/BPatch_type.C b/dyninstAPI/src/BPatch_type.C index f147939959..233f196346 100644 --- a/dyninstAPI/src/BPatch_type.C +++ b/dyninstAPI/src/BPatch_type.C @@ -47,10 +47,10 @@ using namespace Dyninst; using namespace Dyninst::SymtabAPI; -AnnotationClass CommonBlockUpPtrAnno("CommonBlockUpPtr"); -AnnotationClass LocalVarUpPtrAnno("LocalVarUpPtrAnno"); -AnnotationClass FieldUpPtrAnno("FieldUpPtrAnno"); -AnnotationClass TypeUpPtrAnno("TypeUpPtr"); +AnnotationClass CommonBlockUpPtrAnno("CommonBlockUpPtr", nullptr); +AnnotationClass LocalVarUpPtrAnno("LocalVarUpPtrAnno", nullptr); +AnnotationClass FieldUpPtrAnno("FieldUpPtrAnno", nullptr); +AnnotationClass TypeUpPtrAnno("TypeUpPtr", nullptr); //static int findIntrensicType(const char *name); // This is the ID that is decremented for each type a user defines. It is diff --git a/dyninstAPI/src/function.C b/dyninstAPI/src/function.C index 88142f3dee..36e3d1d68a 100644 --- a/dyninstAPI/src/function.C +++ b/dyninstAPI/src/function.C @@ -1641,13 +1641,13 @@ void func_instance::createTMap_internal(StackMod* mod, TMap* tMap) } AnnotationClass - Stack_Anno_Intervals(std::string("Stack_Anno_Intervals")); + Stack_Anno_Intervals(std::string("Stack_Anno_Intervals"), nullptr); AnnotationClass - Stack_Anno_Block_Effects(std::string("Stack_Anno_Block_Effects")); + Stack_Anno_Block_Effects(std::string("Stack_Anno_Block_Effects"), nullptr); AnnotationClass - Stack_Anno_Insn_Effects(std::string("Stack_Anno_Insn_Effects")); + Stack_Anno_Insn_Effects(std::string("Stack_Anno_Insn_Effects"), nullptr); AnnotationClass - Stack_Anno_Call_Effects(std::string("Stack_Anno_Call_Effects")); + Stack_Anno_Call_Effects(std::string("Stack_Anno_Call_Effects"), nullptr); void func_instance::freeStackMod() { // Free stack analysis intervals StackAnalysis::Intervals *i = NULL; diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index 19afb909bf..4b01307073 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -81,8 +81,8 @@ // For callbacks #include "dyninstAPI/src/mapped_object.h" -AnnotationClass ImageVariableUpPtrAnno("ImageVariableUpPtrAnno"); -AnnotationClass ImageFuncUpPtrAnno("ImageFuncUpPtrAnno"); +AnnotationClass ImageVariableUpPtrAnno("ImageVariableUpPtrAnno", nullptr); +AnnotationClass ImageFuncUpPtrAnno("ImageFuncUpPtrAnno", nullptr); pdvector allImages; using namespace std; From 447ee38d53f8d295d7c5b5c1dbb7c19941c7c5d4 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 24 Oct 2016 16:49:46 -0500 Subject: [PATCH 149/180] Add IDE directory to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index af40c844e6..d4603434e6 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ doxyfiles/* */Debug/ */Release/ cotire/ +.idea/* \ No newline at end of file From e8d78c6123323a80ac0097b835ee7560e318e2cf Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 25 Oct 2016 11:18:35 -0500 Subject: [PATCH 150/180] Tweak boost as external project settings --- cmake/packages.cmake | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index c500533830..e1733acd01 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -132,14 +132,28 @@ find_package (Boost ${BOOST_MIN_VERSION} COMPONENTS thread system date_time) if(NOT Boost_FOUND) + set (BOOST_ARGS + --with-system + --with-thread + --with-date_time + --ignore-site-config + --link=static + --runtime-link=shared + --threading=multi) + set(BOOST_BUILD "./b2") if(WIN32) set(BOOST_BOOTSTRAP call bootstrap.bat) - set(BOOST_BUILD b2.exe) set(BOOST_BASE boost/src/Boost) + list(APPEND BOOST_ARGS --layout=versioned) else() set(BOOST_BOOTSTRAP "./bootstrap.sh") - set(BOOST_BUILD "./b2") set(BOOST_BASE boost/src/boost) + list(APPEND BOOST_ARGS --layout=tagged) + endif() + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + list(APPEND BOOST_ARGS variant=debug) + else() + list(APPEND BOOST_ARGS variant=release) endif() message(STATUS "No boost found, attempting to build as external project") @@ -151,8 +165,8 @@ if(NOT Boost_FOUND) URL_MD5 bb1dad35ad069e8d7c8516209a51053c BUILD_IN_SOURCE 1 CONFIGURE_COMMAND ${BOOST_BOOTSTRAP} --prefix=${CMAKE_INSTALL_PREFIX} - BUILD_COMMAND ${BOOST_BUILD} --with-system --with-thread --with-date_time --layout=versioned --ignore-site-config stage - INSTALL_COMMAND ${BOOST_BUILD} --with-system --with-thread --with-date_time --layout=versioned --ignore-site-config install + BUILD_COMMAND ${BOOST_BUILD} ${BOOST_ARGS} stage + INSTALL_COMMAND ${BOOST_BUILD} ${BOOST_ARGS} install ) set(Boost_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}) set(Boost_LIBRARY_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}/stage/lib) From 0124a7f774fb95be5d37ac5caa72ababe5a5020a Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 31 Oct 2016 11:01:46 -0500 Subject: [PATCH 151/180] Disable boost auto-link on Windows and have it always manually link (only). --- cmake/shared.cmake | 3 ++- common/CMakeLists.txt | 11 ++++------- dyninstAPI/CMakeLists.txt | 2 +- instructionAPI/CMakeLists.txt | 4 +--- parseAPI/CMakeLists.txt | 7 +++---- proccontrol/CMakeLists.txt | 2 +- 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 0a8131c456..5240e1dfae 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -5,6 +5,7 @@ set (DYNINST_PATCH_VERSION 0) # Debugging set(Boost_DEBUG 1) +add_definitions(-DBOOST_ALL_NO_LIB=1) set (SOVERSION "${DYNINST_MAJOR_VERSION}.${DYNINST_MINOR_VERSION}") set (LIBVERSION "${SOVERSION}.${DYNINST_PATCH_VERSION}") set (DYNINST_VERSION "${LIBVERSION}") @@ -173,4 +174,4 @@ endif() # Just build vanilla versions, boost can handle it. if (MSVC) add_definitions(-DBOOST_NO_CXX11_VARIADIC_TEMPLATES) -endif() \ No newline at end of file +endif() diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 7c83397cc5..eb053e27c0 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -106,21 +106,18 @@ SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX) ADD_DEFINITIONS(-DCOMMON_LIB) -set (DEPS "") if (IBERTY_FOUND) -set(DEPS "${DEPS};${IBERTY_LIBRARIES}") +set(DEPS ${IBERTY_LIBRARIES}) endif() -dyninst_library(common ${DEPS}) -if (UNIX) - # Boost auto-links on Windows; don't double-link - target_link_private_libraries(common ${Boost_LIBRARIES}) -endif() +list(APPEND DEPS ${Boost_LIBRARIES}) +dyninst_library(common ${DEPS}) if(PLATFORM MATCHES nt OR PLATFORM MATCHES windows) target_link_private_libraries(common Psapi WS2_32 dbghelp) endif() + IF (USE_COTIRE) cotire(common) ENDIF() diff --git a/dyninstAPI/CMakeLists.txt b/dyninstAPI/CMakeLists.txt index 2bf4d60fc7..58bf0f82e1 100644 --- a/dyninstAPI/CMakeLists.txt +++ b/dyninstAPI/CMakeLists.txt @@ -194,9 +194,9 @@ endif () dyninst_library(dyninstAPI common instructionAPI stackwalk pcontrol patchAPI parseAPI symtabAPI) +target_link_private_libraries(dyninstAPI ${Boost_LIBRARIES}) if (UNIX) # Boost auto-links on Windows; don't double-link - target_link_private_libraries(dyninstAPI ${Boost_LIBRARIES}) target_link_private_libraries (dyninstAPI pthread) else() target_link_private_libraries(dyninstAPI dbghelp WS2_32 imagehlp) diff --git a/instructionAPI/CMakeLists.txt b/instructionAPI/CMakeLists.txt index 4e8edb273c..d2ca3fa45c 100644 --- a/instructionAPI/CMakeLists.txt +++ b/instructionAPI/CMakeLists.txt @@ -35,9 +35,7 @@ ADD_DEFINITIONS(-DINSTRUCTION_LIB) dyninst_library(instructionAPI common) -if(UNIX) - target_link_private_libraries(instructionAPI ${Boost_LIBRARIES}) -endif() +target_link_private_libraries(instructionAPI ${Boost_LIBRARIES}) if (USE_COTIRE) cotire(instructionAPI) diff --git a/parseAPI/CMakeLists.txt b/parseAPI/CMakeLists.txt index 45cfa9aadc..2e10338cb5 100644 --- a/parseAPI/CMakeLists.txt +++ b/parseAPI/CMakeLists.txt @@ -134,10 +134,9 @@ endif() dyninst_library(parseAPI common instructionAPI ${SYMREADER}) -if (UNIX) - # Boost auto-links on Windows; don't double-link - target_link_private_libraries(parseAPI ${Boost_LIBRARIES}) -elseif(WIN32) +target_link_private_libraries(parseAPI ${Boost_LIBRARIES}) + +if (WIN32) target_link_private_libraries(parseAPI shlwapi) endif() diff --git a/proccontrol/CMakeLists.txt b/proccontrol/CMakeLists.txt index 5e072beb04..b292c49260 100644 --- a/proccontrol/CMakeLists.txt +++ b/proccontrol/CMakeLists.txt @@ -95,10 +95,10 @@ set (DEPS common ${SYMREADER}) dyninst_library(pcontrol ${DEPS}) target_link_private_libraries(pcontrol ${CMAKE_DL_LIBS}) +target_link_private_libraries(pcontrol ${Boost_LIBRARIES}) if (UNIX) # Boost auto-links on Windows; don't double-link -target_link_private_libraries(pcontrol ${Boost_LIBRARIES}) target_link_private_libraries(pcontrol pthread) endif() if (USE_COTIRE) From 1ae77888d113fa2ef357f054bd6d9201c9abfbb3 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 26 Oct 2016 12:12:34 -0500 Subject: [PATCH 152/180] Explicitly link Symtab against Boost libs --- CMakeLists.txt | 2 +- appveyor.yml | 2 +- cmake/packages.cmake | 4 ++-- common/CMakeLists.txt | 2 +- symtabAPI/CMakeLists.txt | 5 +++-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 710a5b3f4d..6d37955bef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,6 +220,6 @@ if(UNIX) endif() endif() -if(NOT Boost_FOUND) +if(TARGET boost) add_dependencies(common boost) endif() diff --git a/appveyor.yml b/appveyor.yml index 841e3ff925..82713952b8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ build: parallel: true project: Dyninst.sln - verbosity: detailed + verbosity: normal clone_depth: 5 diff --git a/cmake/packages.cmake b/cmake/packages.cmake index e1733acd01..652ef21662 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -166,11 +166,11 @@ if(NOT Boost_FOUND) BUILD_IN_SOURCE 1 CONFIGURE_COMMAND ${BOOST_BOOTSTRAP} --prefix=${CMAKE_INSTALL_PREFIX} BUILD_COMMAND ${BOOST_BUILD} ${BOOST_ARGS} stage - INSTALL_COMMAND ${BOOST_BUILD} ${BOOST_ARGS} install + INSTALL_COMMAND "" ) set(Boost_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}) set(Boost_LIBRARY_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}/stage/lib) - set(Boost_LIBRARIES -lboost_system -lboost_thread) + set(Boost_LIBRARIES boost_thread boost_system) endif() link_directories ( ${Boost_LIBRARY_DIRS} ) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index eb053e27c0..62b09f7e19 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -110,12 +110,12 @@ if (IBERTY_FOUND) set(DEPS ${IBERTY_LIBRARIES}) endif() -list(APPEND DEPS ${Boost_LIBRARIES}) dyninst_library(common ${DEPS}) if(PLATFORM MATCHES nt OR PLATFORM MATCHES windows) target_link_private_libraries(common Psapi WS2_32 dbghelp) endif() +target_link_private_libraries(common ${Boost_LIBRARIES}) IF (USE_COTIRE) diff --git a/symtabAPI/CMakeLists.txt b/symtabAPI/CMakeLists.txt index 88bde95b02..ed2d29df6b 100644 --- a/symtabAPI/CMakeLists.txt +++ b/symtabAPI/CMakeLists.txt @@ -100,15 +100,16 @@ ADD_DEFINITIONS(-DSYMTAB_LIB) set (DEPS common) if(UNIX) - set (DEPS ${DEPS} + list (APPEND DEPS dynElf ${LIBELF_LIBRARIES} dynDwarf ${LIBDWARF_LIBRARIES} ) else() - set (DEPS ${DEPS} dbghelp) + list (APPEND DEPS dbghelp) endif() dyninst_library(symtabAPI ${DEPS}) +target_link_private_libraries(symtabAPI ${Boost_LIBRARIES}) if (USE_COTIRE) cotire(symtabAPI) From 171e651e446658421def21a6799e1ac8fdf442d8 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 27 Oct 2016 11:27:40 -0500 Subject: [PATCH 153/180] Set boost lib layout to system--we're building one set of static libs to link in invisibly, and they should match the Dyninst toolchain. --- cmake/packages.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index 652ef21662..ef6f4cf802 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -144,7 +144,8 @@ if(NOT Boost_FOUND) if(WIN32) set(BOOST_BOOTSTRAP call bootstrap.bat) set(BOOST_BASE boost/src/Boost) - list(APPEND BOOST_ARGS --layout=versioned) + list(APPEND BOOST_ARGS --layout=system) + set(BOOST_LIB_PREFIX lib) else() set(BOOST_BOOTSTRAP "./bootstrap.sh") set(BOOST_BASE boost/src/boost) @@ -170,7 +171,7 @@ if(NOT Boost_FOUND) ) set(Boost_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}) set(Boost_LIBRARY_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}/stage/lib) - set(Boost_LIBRARIES boost_thread boost_system) + set(Boost_LIBRARIES ${BOOST_LIB_PREFIX}boost_thread ${BOOST_LIB_PREFIX}boost_system ${BOOST_LIB_PREFIX}boost_date_time) endif() link_directories ( ${Boost_LIBRARY_DIRS} ) From c48ebb256caf5880f7cfc07946ee9aec87b00a01 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 27 Oct 2016 12:03:24 -0500 Subject: [PATCH 154/180] Disable multi-index serialization so we'll actually link. --- cmake/packages.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index ef6f4cf802..9d9b7fd8c8 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -179,7 +179,7 @@ link_directories ( ${Boost_LIBRARY_DIRS} ) include_directories ( ${Boost_INCLUDE_DIRS} ) - +add_definitions(-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION) message(STATUS "Boost includes: ${Boost_INCLUDE_DIRS}") message(STATUS "Boost library dirs: ${Boost_LIBRARY_DIRS}") message(STATUS "Boost thread library: ${Boost_THREAD_LIBRARY}") From 30a3a26778a8ffba01ecb0886b48d4d49b0c8202 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 27 Oct 2016 16:51:42 -0500 Subject: [PATCH 155/180] Revert to dumb pointers for compatibility within line info interfaces, but add Ptr/ConstPtr typedefs. --- dyninstAPI/h/BPatch_statement.h | 13 +++---------- symtabAPI/h/Module.h | 6 ++++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/dyninstAPI/h/BPatch_statement.h b/dyninstAPI/h/BPatch_statement.h index b4a434d4b9..5d96d59aa2 100644 --- a/dyninstAPI/h/BPatch_statement.h +++ b/dyninstAPI/h/BPatch_statement.h @@ -32,16 +32,9 @@ #define _BPATCH_STATEMENT_H_ #include "BPatch_dll.h" -#include - +#include "Module.h" class BPatch_module; -namespace Dyninst { -namespace SymtabAPI { - class Statement; - typedef boost::shared_ptr StatementConstPtr; -} -} class BPATCH_DLL_EXPORT BPatch_statement { @@ -81,10 +74,10 @@ class BPATCH_DLL_EXPORT BPatch_statement private: // Full parameter ctor -- can only built by friend classes - BPatch_statement(BPatch_module *mod, Dyninst::SymtabAPI::StatementConstPtr s); + BPatch_statement(BPatch_module *mod, Dyninst::SymtabAPI::Statement::ConstPtr s); BPatch_module *module_; - Dyninst::SymtabAPI::StatementConstPtr statement; + Dyninst::SymtabAPI::Statement::ConstPtr statement; }; #endif diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index de55990ebb..0b40979186 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -109,8 +109,10 @@ class SYMTAB_EXPORT Statement : public AddressRange struct line_info {}; struct upper_bound {}; - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; + typedef Statement* Ptr; + typedef const Statement* ConstPtr; +// typedef boost::shared_ptr Ptr; +// typedef boost::shared_ptr ConstPtr; }; template From 7c398cf442312f41cc439ea11b2f79f4c2d6c977 Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Mon, 31 Oct 2016 11:45:14 -0500 Subject: [PATCH 156/180] Add missing #include from SymReader changes. --- symtabAPI/src/Object-nt.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index d5fd138408..9d0231396c 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -52,7 +52,7 @@ #include "Function.h" #include "Variable.h" #include "emitWin.h" - +#include "SymReader.h" #include "common/src/headers.h" using namespace Dyninst; From 42888dbc168549edb14ad1ba2c4a33bf5778d40d Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Tue, 1 Nov 2016 13:07:04 -0500 Subject: [PATCH 157/180] Cleanup to get test suite building and passing locally (including some de-confusing of stream operators). --- common/h/IBSTree-fast.h | 7 ++++ common/h/IBSTree.h | 19 ++++++++- dataflowAPI/h/Absloc.h | 16 +++++-- dataflowAPI/h/SymEval.h | 15 +++++++ dataflowAPI/h/stackanalysis.h | 7 +++- dataflowAPI/src/Absloc.C | 13 ------ dyninstAPI/src/Relocation/CodeTracker.C | 55 ++++++++++++++----------- dyninstAPI/src/Relocation/CodeTracker.h | 6 +-- symtabAPI/h/Module.h | 1 - symtabAPI/h/RangeLookup.h | 25 ++++++----- symtabAPI/src/LineInformation.C | 8 +++- symtabAPI/src/Symtab-lookup.C | 4 +- 12 files changed, 112 insertions(+), 64 deletions(-) diff --git a/common/h/IBSTree-fast.h b/common/h/IBSTree-fast.h index 2719a9160b..48c6fd4551 100644 --- a/common/h/IBSTree-fast.h +++ b/common/h/IBSTree-fast.h @@ -178,6 +178,13 @@ namespace Dyninst void successor(interval_type X, std::set& ) const; ITYPE* successor(interval_type X) const; void clear(); + friend std::ostream& operator<<(std::ostream& stream, const IBSTree_fast& tree) + { + std::copy(tree.unique_intervals.begin(), tree.unique_intervals.end(), + std::ostream_iterator::interval_set::value_type>(stream, "\n")); + stream << tree.overlapping_intervals; + return stream; + } }; diff --git a/common/h/IBSTree.h b/common/h/IBSTree.h index 9a4b0a5878..79f8099ee1 100644 --- a/common/h/IBSTree.h +++ b/common/h/IBSTree.h @@ -132,6 +132,15 @@ class IBSNode { interval_type value() const { return val_; }; interval_type operator*() const { return value; } + friend std::ostream& operator<<(std::ostream& stream, const IBSNode& node) + { + if(node.left) stream << *(node.left); + stream << node.val_ << std::endl; + if(node.right) stream << *(node.right); + return stream; + + } + private: /* The endpoint of an interval range */ @@ -215,6 +224,10 @@ class IBSTree { int CountMarks(IBSNode *R) const; unsigned MemUse() const; + friend std::ostream& operator<<(std::ostream& stream, const IBSTree& tree) + { + return stream << *(tree.root); + }; public: @@ -888,11 +901,15 @@ void IBSTree::PrintPreorder(IBSNode *n) } } + + template int IBSTree::CountMarks() const { return CountMarks(root); } -} /* Dyninst */ +}/* Dyninst */ + + #endif diff --git a/dataflowAPI/h/Absloc.h b/dataflowAPI/h/Absloc.h index f486edbcd5..a136716c0a 100644 --- a/dataflowAPI/h/Absloc.h +++ b/dataflowAPI/h/Absloc.h @@ -179,6 +179,11 @@ class Absloc { } }; + friend std::ostream &operator<<(std::ostream &os, const Absloc &a) { + os << a.format(); + return os; + } + private: Type type_; @@ -253,6 +258,10 @@ class AbsRegion { DATAFLOW_EXPORT AST::Ptr generator() const { return generator_; } DATAFLOW_EXPORT bool isImprecise() const { return type_ != Absloc::Unknown; } + friend std::ostream &operator<<(std::ostream &os, const AbsRegion &a) { + os << a.format(); + return os; + } private: // Type is for "we're on the stack but we don't know where". @@ -349,6 +358,10 @@ class Assignment { DATAFLOW_EXPORT ParseAPI::Function *func() const { return func_; } DATAFLOW_EXPORT ParseAPI::Block *block() const { return block_; } + friend std::ostream &operator<<(std::ostream &os, const Assignment::Ptr &a) { + os << a->format(); + return os; + } private: InstructionAPI::Instruction::Ptr insn_; @@ -376,9 +389,6 @@ struct AssignmentPtrValueComp { }; -std::ostream &operator<<(std::ostream &os, const Dyninst::Absloc &a); -std::ostream &operator<<(std::ostream &os, const Dyninst::AbsRegion &a); -std::ostream &operator<<(std::ostream &os, const Dyninst::Assignment::Ptr &a); #endif diff --git a/dataflowAPI/h/SymEval.h b/dataflowAPI/h/SymEval.h index e0c728fd59..6f57e3f123 100644 --- a/dataflowAPI/h/SymEval.h +++ b/dataflowAPI/h/SymEval.h @@ -94,6 +94,11 @@ struct Variable { ret << ")"; return ret.str(); } + friend std::ostream& operator<<(std::ostream& stream, const Variable& c) + { + stream << c.format() << std::endl; + return stream; + } AbsRegion reg; Address addr; @@ -122,6 +127,11 @@ struct Constant { } return ret.str(); } +friend std::ostream& operator<<(std::ostream& stream, const Constant& c) +{ + stream << c.format() << std::endl; + return stream; +} uint64_t val; size_t size; @@ -278,6 +288,11 @@ DATAFLOW_EXPORT const std::string format() const { ret << ">"; return ret.str(); }; + friend std::ostream& operator<<(std::ostream& stream, const ROSEOperation& c) + { + stream << c.format() << std::endl; + return stream; + } Op op; size_t size; diff --git a/dataflowAPI/h/stackanalysis.h b/dataflowAPI/h/stackanalysis.h index 94f9f52ab0..0f2f19cded 100644 --- a/dataflowAPI/h/stackanalysis.h +++ b/dataflowAPI/h/stackanalysis.h @@ -131,6 +131,11 @@ class StackAnalysis { retVal << height_; return retVal.str(); } + friend std::ostream& operator<<(std::ostream& stream, const Height& c) + { + stream << c.format() << std::endl; + return stream; + } bool isBottom() const { return type_ == BOTTOM && height_ == notUnique; @@ -466,8 +471,6 @@ class StackAnalysis { } // namespace Dyninst -DATAFLOW_EXPORT std::ostream &operator<<(std::ostream &os, - const Dyninst::StackAnalysis::Height &h); namespace Dyninst { DEF_AST_LEAF_TYPE(StackAST, Dyninst::StackAnalysis::Height); diff --git a/dataflowAPI/src/Absloc.C b/dataflowAPI/src/Absloc.C index 1451a4edaa..ebea96465b 100644 --- a/dataflowAPI/src/Absloc.C +++ b/dataflowAPI/src/Absloc.C @@ -336,20 +336,7 @@ const std::string Assignment::format() const { return ret.str(); } -std::ostream &operator<<(std::ostream &os, const Absloc &a) { - os << a.format(); - return os; -} - -std::ostream &operator<<(std::ostream &os, const AbsRegion &a) { - os << a.format(); - return os; -} -std::ostream &operator<<(std::ostream &os, const Assignment::Ptr &a) { - os << a->format(); - return os; -} #if 0 bool AbsRegion::equivalent(const AbsRegion &lhs, diff --git a/dyninstAPI/src/Relocation/CodeTracker.C b/dyninstAPI/src/Relocation/CodeTracker.C index fe40c2d11f..bac504081e 100644 --- a/dyninstAPI/src/Relocation/CodeTracker.C +++ b/dyninstAPI/src/Relocation/CodeTracker.C @@ -227,28 +227,35 @@ void CodeTracker::debug() { cerr << endl; } -std::ostream &operator<<(std::ostream &os, const Dyninst::Relocation::TrackerElement &e) { - os << "Tracker(" << hex - << e.orig() << "," << e.reloc() - << "," << dec << e.size(); - switch(e.type()) { - case TrackerElement::original: - os << ",o"; - break; - case TrackerElement::emulated: - os << ",e"; - break; - case TrackerElement::instrumentation: - os << ",i"; - break; - case TrackerElement::padding: - os << ",p"; - break; - default: - os << ",?"; - break; - } - os << "," << e.block()->start() << "," << (e.func() ? e.func()->name() : ""); - os << ")" << dec; - return os; +namespace Dyninst +{ + namespace Relocation + { + std::ostream &operator<<(std::ostream &os, const Dyninst::Relocation::TrackerElement &e) { + os << "Tracker(" << hex + << e.orig() << "," << e.reloc() + << "," << dec << e.size(); + switch(e.type()) { + case TrackerElement::original: + os << ",o"; + break; + case TrackerElement::emulated: + os << ",e"; + break; + case TrackerElement::instrumentation: + os << ",i"; + break; + case TrackerElement::padding: + os << ",p"; + break; + default: + os << ",?"; + break; + } + os << "," << e.block()->start() << "," << (e.func() ? e.func()->name() : ""); + os << ")" << dec; + return os; + } + + } } diff --git a/dyninstAPI/src/Relocation/CodeTracker.h b/dyninstAPI/src/Relocation/CodeTracker.h index a991827850..3db0e06ba3 100644 --- a/dyninstAPI/src/Relocation/CodeTracker.h +++ b/dyninstAPI/src/Relocation/CodeTracker.h @@ -84,7 +84,7 @@ class TrackerElement { void setReloc(Address reloc) { reloc_ = reloc; }; void setSize(unsigned size) { size_ = size; } - virtual bool mergeable() const { return true; } + virtual bool mergeable() const { return true; } protected: TrackerElement() { assert(0); }; @@ -119,6 +119,8 @@ class OriginalTracker : public TrackerElement { private: }; + std::ostream & + operator<<(std::ostream &os, const Dyninst::Relocation::TrackerElement &e); class EmulatorTracker : public TrackerElement { public: @@ -276,7 +278,5 @@ class CodeTracker { }; }; -std::ostream & -operator<<(std::ostream &os, const Dyninst::Relocation::TrackerElement &e); #endif diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 0b40979186..aebd6d3125 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -85,7 +85,6 @@ class SYMTAB_EXPORT Statement : public AddressRange }; typedef StatementLess LineNoTupleLess; - bool operator==(const Statement &cmp) const; // bool operator==(const char* file) const {return strcmp(file, first) == 0; } bool operator==(Offset addr) const { diff --git a/symtabAPI/h/RangeLookup.h b/symtabAPI/h/RangeLookup.h index 6e113764e8..b9d79434b3 100644 --- a/symtabAPI/h/RangeLookup.h +++ b/symtabAPI/h/RangeLookup.h @@ -52,19 +52,9 @@ namespace Dyninst { struct SYMTAB_EXPORT AddressRange : std::pair { template - AddressRange(T t) { - first = t.startAddr(); - second = t.endAddr(); - } - template - AddressRange(typename boost::shared_ptr t) { - first = t->startAddr(); - second = t->endAddr(); - } - template - AddressRange(T* t) { - first = t->startAddr(); - second = t->endAddr(); + AddressRange(Dyninst::SimpleInterval i) { + first = i.low(); + second = i.high(); } AddressRange(Offset t) { @@ -76,6 +66,15 @@ namespace Dyninst { first = start; second = end; } + AddressRange(const AddressRange& other) : std::pair(other) + { + } + AddressRange& operator=(const AddressRange& other) + { + first = other.first; + second = other.second; + return *this; + } AddressRange merge(const AddressRange& other) { return AddressRange(std::min(first, other.first), std::max(second, other.second)); diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 1b4251299c..dc32a8a332 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -139,8 +139,12 @@ bool LineInformation::getAddressRanges( const char * lineSource, unsigned int lineNo, vector< AddressRange > & ranges ) { auto found_statements = equal_range(lineSource, lineNo); - std::copy(found_statements.first, found_statements.second, - std::back_inserter(ranges)); + for(auto i = found_statements.first; + i != found_statements.second; + ++i) + { + ranges.push_back(AddressRange(**i)); + } return found_statements.first != found_statements.second; } /* end getAddressRangesFromLine() */ diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 1625939c41..5ded0c4d43 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -392,7 +392,7 @@ bool Symtab::findModuleByOffset(Module *&ret, Offset off) { ret = (*mods.begin())->id(); } - return mods.empty(); + return !mods.empty(); } bool Symtab::findModuleByOffset(std::set&ret, Offset off) @@ -406,7 +406,7 @@ bool Symtab::findModuleByOffset(std::set&ret, Offset off) { ret.insert((*i)->id()); } - return ret.empty(); + return !ret.empty(); } bool Symtab::findModuleByName(Module *&ret, const std::string name) From 15aa7e0c10bb8f43f9999b98de841c7be402dc9c Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 2 Nov 2016 11:38:45 -0500 Subject: [PATCH 158/180] Remove redundant stream operator definitions to make CLang happy --- dataflowAPI/h/SymEval.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dataflowAPI/h/SymEval.h b/dataflowAPI/h/SymEval.h index 6f57e3f123..17511d62fd 100644 --- a/dataflowAPI/h/SymEval.h +++ b/dataflowAPI/h/SymEval.h @@ -302,10 +302,6 @@ size_t size; }; -// Get this out of the Dyninst namespace... -DATAFLOW_EXPORT std::ostream &operator<<(std::ostream &os, const Dyninst::DataflowAPI::ROSEOperation &o); -DATAFLOW_EXPORT std::ostream &operator<<(std::ostream &os, const Dyninst::DataflowAPI::Constant &o); -DATAFLOW_EXPORT std::ostream &operator<<(std::ostream &os, const Dyninst::DataflowAPI::Variable &o); namespace Dyninst { From 59c79c6b818b02f83cd6530fff962ffa6e5f0829 Mon Sep 17 00:00:00 2001 From: Sunny Shah Date: Fri, 4 Nov 2016 12:14:35 -0500 Subject: [PATCH 159/180] Fix for decoding error in register based load/store instructions The shift amount for the second source register in load/store (register) instructions should depend only on the value of the 'S' field. --- instructionAPI/src/InstructionDecoder-aarch64.C | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/instructionAPI/src/InstructionDecoder-aarch64.C b/instructionAPI/src/InstructionDecoder-aarch64.C index 2e01366c72..408c6edcd2 100644 --- a/instructionAPI/src/InstructionDecoder-aarch64.C +++ b/instructionAPI/src/InstructionDecoder-aarch64.C @@ -1492,19 +1492,12 @@ Expression::Ptr InstructionDecoder_aarch64::makeMemRefExPair2(){ int immLen = 2; int immVal = 0; //for amount - int S = field<12, 12>(insn); int size = field<30, 31>(insn); - if (size == 2) { //32bit - immVal = S == 0 ? 0 : (S == 1 ? 2 : -1); - if (immVal == -1) - isValid = false; - } - else if (size == 3) { //64bit - immVal = S == 0 ? 0 : (S == 1 ? 3 : -1); - if (immVal == -1) - isValid = false; - } + if(sField == 1) + immVal = size; + else + immVal = 0; Expression::Ptr ext = makeOptionExpression(immLen, immVal); From 1838c82e65ec244018c2892d725cac092621fa9b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Nov 2016 12:06:31 -0700 Subject: [PATCH 160/180] common: include ostream in IBSTree.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's needed to solve this error with GCC 6.2: common/h/IBSTree.h:138:32: error: ‘endl’ is not a member of ‘std’ stream << node.val_ << std::endl; ^~~ --- common/h/IBSTree.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/h/IBSTree.h b/common/h/IBSTree.h index 79f8099ee1..e55c8a737c 100644 --- a/common/h/IBSTree.h +++ b/common/h/IBSTree.h @@ -44,6 +44,7 @@ #include #include +#include /** Template class for Interval Binary Search Tree. The implementation is * based on a red-black tree (derived from our codeRange implementation) From f1fa9ef37b29c3e12b4b5489ec05ad6cd7168175 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Nov 2016 18:31:28 -0700 Subject: [PATCH 161/180] proccontrol: Synchronize additional threads found during attach When additional threads are found during the attach process, we should synchronize to their stopping point, and check for new threads again, until no new threads are found. This keeps a more consistent state if threads are racing to start while we're attaching. --- proccontrol/src/int_process.h | 2 ++ proccontrol/src/process.C | 58 ++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/proccontrol/src/int_process.h b/proccontrol/src/int_process.h index f389175a0a..20a8648a79 100644 --- a/proccontrol/src/int_process.h +++ b/proccontrol/src/int_process.h @@ -271,7 +271,9 @@ class int_process static bool reattach(int_processSet *pset); virtual bool plat_attach(bool allStopped, bool &should_sync) = 0; + bool attachThreads(bool &found_new_threads); bool attachThreads(); + bool attachThreadsSync(); virtual async_ret_t post_attach(bool wasDetached, std::set &aresps); async_ret_t initializeAddressSpace(std::set &async_responses); diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C index 1522a7577e..5df445b520 100644 --- a/proccontrol/src/process.C +++ b/proccontrol/src/process.C @@ -211,8 +211,10 @@ void int_process::plat_threadAttachDone() { } -bool int_process::attachThreads() +bool int_process::attachThreads(bool &found_new_threads) { + found_new_threads = false; + if (!needIndividualThreadAttach()) return true; @@ -224,9 +226,9 @@ bool int_process::attachThreads() * a list of LWPs, but then new threads are created before we attach to * all the existing threads. **/ - bool found_new_threads; + bool loop_new_threads; do { - found_new_threads = false; + loop_new_threads = false; vector lwps; bool result = getThreadLWPs(lwps); if (!result) { @@ -242,13 +244,56 @@ bool int_process::attachThreads() } pthrd_printf("Creating new thread for %d/%d during attach\n", pid, *i); thr = int_thread::createThread(this, NULL_THR_ID, *i, false, int_thread::as_needs_attach); - found_new_threads = true; + found_new_threads = loop_new_threads = true; } - } while (found_new_threads); + } while (loop_new_threads); return true; } +bool int_process::attachThreads() +{ + bool found_new_threads = false; + return attachThreads(found_new_threads); +} + +// Attach any new threads and synchronize, until there are no new threads +bool int_process::attachThreadsSync() +{ + while (true) { + bool found_new_threads = false; + + ProcPool()->condvar()->lock(); + bool result = attachThreads(found_new_threads); + if (found_new_threads) + ProcPool()->condvar()->broadcast(); + ProcPool()->condvar()->unlock(); + + if (!result) { + pthrd_printf("Failed to attach to threads in %d\n", pid); + setLastError(err_internal, "Could not get threads during attach\n"); + return false; + } + + if (!found_new_threads) + return true; + + pthrd_printf("Wait again for attach from process %d\n", pid); + bool proc_exited = false; + result = waitAndHandleForProc(true, this, proc_exited); + if (!result) { + perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid()); + setLastError(err_internal, "Error while calling waitAndHandleForProc for attached threads\n"); + return false; + } + if (proc_exited) { + perr_printf("Process exited while waiting for user thread stop, erroring\n"); + setLastError(err_exited, "Process exited while thread being stopped.\n"); + return false; + } + } +} + bool int_process::attach(int_processSet *ps, bool reattach) { bool had_error = false, should_sync = false; @@ -443,10 +488,9 @@ bool int_process::attach(int_processSet *ps, bool reattach) int_process *proc = *i; if (proc->getState() == errorstate) continue; - bool result = proc->attachThreads(); + bool result = proc->attachThreadsSync(); if (!result) { pthrd_printf("Failed to attach to threads in %d--now an error\n", proc->pid); - proc->setLastError(err_internal, "Could not get threads during attach\n"); procs.erase(i++); had_error = true; continue; From 75bc5ac9f1a1c804b38e183aa09f33097370c8e4 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Wed, 6 Jul 2016 09:58:54 -0400 Subject: [PATCH 162/180] fix icc warning flags --- cmake/warnings.cmake | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake index d32b97d3ea..ca3b779269 100644 --- a/cmake/warnings.cmake +++ b/cmake/warnings.cmake @@ -1,9 +1,10 @@ -if (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_C_COMPILER_ID} MATCHES INTEL) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Wcast-align") -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual -Wcast-align -Wno-non-template-friend -Wno-unused-local-typedefs -Wno-deprecated-declarations") -elseif (${CMAKE_C_COMPILER_ID} MATCHES Clang) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual") -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual") +if (CMAKE_COMPILER_IS_GNUCXX) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wpointer-arith -Wcast-qual -Woverloaded-virtual") +if (CMAKE_C_COMPILER_ID MATCHES GNU) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-align") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-align -Wno-non-template-friend -Wno-unused-local-typedefs -Wno-deprecated-declarations") +endif (CMAKE_C_COMPILER_ID) elseif (MSVC) message(STATUS "TODO: Set up custom warning flags for MSVC") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4251 /wd4091 /wd4503") From c5fb5f8c75fef57faa846922561358b0cfd40f94 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 6 Nov 2016 00:41:59 -0400 Subject: [PATCH 163/180] Fix warnings --- symtabAPI/src/Module.C | 2 +- symtabAPI/src/Object-elf.C | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index 8d3b7530ec..62e0ef02eb 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -338,11 +338,11 @@ Module::Module(const Module &mod) : LookupInterface(), lineInfo_(mod.lineInfo_), typeInfo_(mod.typeInfo_), + info_(mod.info_), fileName_(mod.fileName_), fullName_(mod.fullName_), language_(mod.language_), addr_(mod.addr_), - info_(mod.info_), exec_(mod.exec_), strings_(mod.strings_), ranges_finalized(mod.ranges_finalized) diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 0c787a5c03..fabc0cbdf8 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -1105,8 +1105,9 @@ bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, } else if (plt_entry_size_ == 16) { // New style secure PLT - Region *plt = NULL, *relplt = NULL, *dynamic = NULL, + Region *plt = NULL, *dynamic = NULL, *got = NULL, *glink = NULL; + // Region *relplt = NULL; unsigned int glink_addr = 0; unsigned int stub_addr = 0; @@ -1116,7 +1117,7 @@ bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, for (unsigned iter = 0; iter < regions_.size(); ++iter) { std::string name = regions_[iter]->getRegionName(); if (name == PLT_NAME) plt = regions_[iter]; - else if (name == REL_PLT_NAME) relplt = regions_[iter]; + // else if (name == REL_PLT_NAME) relplt = regions_[iter]; else if (name == DYNAMIC_NAME) dynamic = regions_[iter]; else if (name == GOT_NAME) got = regions_[iter]; } From a79ba00b9cd3f9b690bd73100c196ad201971a7f Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 6 Nov 2016 11:35:19 -0500 Subject: [PATCH 164/180] fix AddressRange forward declarations --- dyninstAPI/h/BPatch_addressSpace.h | 2 +- dyninstAPI/h/BPatch_image.h | 2 +- dyninstAPI/h/BPatch_module.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dyninstAPI/h/BPatch_addressSpace.h b/dyninstAPI/h/BPatch_addressSpace.h index e33258901e..4f997e36a3 100644 --- a/dyninstAPI/h/BPatch_addressSpace.h +++ b/dyninstAPI/h/BPatch_addressSpace.h @@ -63,7 +63,7 @@ namespace Dyninst { }; namespace SymtabAPI { class Symbol; - class AddressRange; + struct AddressRange; }; } diff --git a/dyninstAPI/h/BPatch_image.h b/dyninstAPI/h/BPatch_image.h index 72e513c9e1..785180242e 100644 --- a/dyninstAPI/h/BPatch_image.h +++ b/dyninstAPI/h/BPatch_image.h @@ -66,7 +66,7 @@ class BPatch_object_getMod; namespace Dyninst { namespace SymtabAPI { - class AddressRange; + struct AddressRange; } namespace PatchAPI { class PatchMgr; diff --git a/dyninstAPI/h/BPatch_module.h b/dyninstAPI/h/BPatch_module.h index 33014112e5..a76748921b 100644 --- a/dyninstAPI/h/BPatch_module.h +++ b/dyninstAPI/h/BPatch_module.h @@ -62,7 +62,7 @@ class BPatch_object; namespace Dyninst { namespace SymtabAPI { class Module; - class AddressRange; + struct AddressRange; BPATCH_DLL_EXPORT Module *convert(const BPatch_module *); } namespace PatchAPI { From 897f0c4a7fd30a34f9b711274c9628b3d76f29ea Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Nov 2016 18:13:28 -0800 Subject: [PATCH 165/180] proccontrol: move thread sync to linux_process, and count neonatal --- proccontrol/src/int_process.h | 3 ++- proccontrol/src/linux.C | 38 +++++++++++++++++++++++++++++++ proccontrol/src/linux.h | 1 + proccontrol/src/process.C | 43 ++++++++--------------------------- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/proccontrol/src/int_process.h b/proccontrol/src/int_process.h index 20a8648a79..0c292f297b 100644 --- a/proccontrol/src/int_process.h +++ b/proccontrol/src/int_process.h @@ -273,7 +273,8 @@ class int_process bool attachThreads(bool &found_new_threads); bool attachThreads(); - bool attachThreadsSync(); + virtual bool plat_attachThreadsSync(); + virtual async_ret_t post_attach(bool wasDetached, std::set &aresps); async_ret_t initializeAddressSpace(std::set &async_responses); diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C index d701693761..573f1f6032 100644 --- a/proccontrol/src/linux.C +++ b/proccontrol/src/linux.C @@ -1110,6 +1110,44 @@ bool linux_process::plat_attach(bool, bool &) return true; } +// Attach any new threads and synchronize, until there are no new threads +bool linux_process::plat_attachThreadsSync() +{ + while (true) { + bool found_new_threads = false; + + ProcPool()->condvar()->lock(); + bool result = attachThreads(found_new_threads); + if (found_new_threads) + ProcPool()->condvar()->broadcast(); + ProcPool()->condvar()->unlock(); + + if (!result) { + pthrd_printf("Failed to attach to threads in %d\n", pid); + setLastError(err_internal, "Could not get threads during attach\n"); + return false; + } + + if (!found_new_threads) + return true; + + while (Counter::processCount(Counter::NeonatalThreads, this) > 0) { + bool proc_exited = false; + pthrd_printf("Waiting for neonatal threads in process %d\n", pid); + result = waitAndHandleForProc(true, this, proc_exited); + if (!result) { + perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid()); + return false; + } + if (proc_exited) { + perr_printf("Process exited while waiting for user thread stop, erroring\n"); + setLastError(err_exited, "Process exited while thread being stopped.\n"); + return false; + } + } + } +} + bool linux_process::plat_attachWillTriggerStop() { char procName[64]; char cmd[256]; diff --git a/proccontrol/src/linux.h b/proccontrol/src/linux.h index 4972fb7114..56326ad9e6 100644 --- a/proccontrol/src/linux.h +++ b/proccontrol/src/linux.h @@ -111,6 +111,7 @@ class linux_process : public sysv_process, public unix_process, public thread_db virtual bool plat_create(); virtual bool plat_create_int(); virtual bool plat_attach(bool allStopped, bool &); + virtual bool plat_attachThreadsSync(); virtual bool plat_attachWillTriggerStop(); virtual bool plat_forked(); virtual bool plat_execed(); diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C index 5df445b520..90bde49ab8 100644 --- a/proccontrol/src/process.C +++ b/proccontrol/src/process.C @@ -257,41 +257,16 @@ bool int_process::attachThreads() return attachThreads(found_new_threads); } -// Attach any new threads and synchronize, until there are no new threads -bool int_process::attachThreadsSync() +bool int_process::plat_attachThreadsSync() { - while (true) { - bool found_new_threads = false; - - ProcPool()->condvar()->lock(); - bool result = attachThreads(found_new_threads); - if (found_new_threads) - ProcPool()->condvar()->broadcast(); - ProcPool()->condvar()->unlock(); - - if (!result) { - pthrd_printf("Failed to attach to threads in %d\n", pid); - setLastError(err_internal, "Could not get threads during attach\n"); - return false; - } - - if (!found_new_threads) - return true; - - pthrd_printf("Wait again for attach from process %d\n", pid); - bool proc_exited = false; - result = waitAndHandleForProc(true, this, proc_exited); - if (!result) { - perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid()); - setLastError(err_internal, "Error while calling waitAndHandleForProc for attached threads\n"); - return false; - } - if (proc_exited) { - perr_printf("Process exited while waiting for user thread stop, erroring\n"); - setLastError(err_exited, "Process exited while thread being stopped.\n"); - return false; - } + // By default, platforms just call the idempotent attachThreads(). + // Some platforms may override, e.g. Linux should sync with all threads. + if (!attachThreads()) { + pthrd_printf("Failed to attach to threads in %d\n", pid); + setLastError(err_internal, "Could not get threads during attach\n"); + return false; } + return true; } bool int_process::attach(int_processSet *ps, bool reattach) @@ -488,7 +463,7 @@ bool int_process::attach(int_processSet *ps, bool reattach) int_process *proc = *i; if (proc->getState() == errorstate) continue; - bool result = proc->attachThreadsSync(); + bool result = proc->plat_attachThreadsSync(); if (!result) { pthrd_printf("Failed to attach to threads in %d--now an error\n", proc->pid); procs.erase(i++); From 4f2b20fe1667bfd29dcf4145038d3cab29693cbd Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Wed, 9 Nov 2016 11:31:16 -0600 Subject: [PATCH 166/180] LibraryTracker documentation --- stackwalk/doc/3-API.tex | 53 ++++++++++++++++++++++++++++++++++++ stackwalk/doc/stackwalk.pdf | Bin 323532 -> 326046 bytes 2 files changed, 53 insertions(+) diff --git a/stackwalk/doc/3-API.tex b/stackwalk/doc/3-API.tex index 389dde9d46..088b913c77 100644 --- a/stackwalk/doc/3-API.tex +++ b/stackwalk/doc/3-API.tex @@ -173,6 +173,59 @@ \subsection{Stackwalking Interface} \input{API/Walker} \input{API/Frame} +\subsection{Mapping Addresses to Libraries} +\definedin{procstate.h} + +StackwalkerAPI provides an interface to access the addresses where libraries are mapped in the +target process. + +\begin{apient} +typedef std::pair LibAddrPair; +\end{apient} +\apidesc{ +A pair consisting of a library filename and its base address in the target process. +} + +\begin{apient} +class LibraryState +\end{apient} +\apidesc{ +Class providing interfaces for library tracking. Only the public query interfaces below are user-facing; the other public +methods are callbacks that allow StackwalkerAPI to update its internal state. +} + +\begin{apient} + virtual bool getLibraryAtAddr(Address addr, LibAddrPair &lib) = 0; +\end{apient} +\apidesc{ +Given an address \code{addr} in the target process, returns \code{true} and sets \code{lib} to the name and base address of the library containing +addr. Given an address outside the target process, returns \code{false}. +} +\begin{apient} + virtual bool getLibraries(std::vector &libs, bool allow\_refresh = true) = 0; +\end{apient} +\apidesc{ +Fills \code{libs} with the libraries loaded in the target process. If \code{allow\_refresh} is true, this method will attempt to ensure +that this list is freshly updated via inspection of the process; if it is false, it will return a cached list. +} +\begin{apient} + virtual bool getLibc(LibAddrPair &lc); +\end{apient} +\apidesc{ +Convenience function to find the name and base address of the standard C runtime, if present. +} +\begin{apient} + virtual bool getLibthread(LibAddrPair <); +\end{apient} +\apidesc{ +Convenience function to find the name and base address of the standard thread library, if present (e.g. pthreads). +} +\begin{apient} + virtual bool getAOut(LibAddrPair &ao) = 0; +\end{apient} +\apidesc{ +Convenience function to find the name and base address of the executable. +} \subsection{Accessing Local Variables} \definedin{local\_var.h} diff --git a/stackwalk/doc/stackwalk.pdf b/stackwalk/doc/stackwalk.pdf index 5046d84f47f3772f40d87f391ae55d06829da3c9..7a90d6c814d2da8404e4d8f227c20c8a81ab27e1 100644 GIT binary patch delta 113671 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 z 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 b+)Z5Fy Date: Thu, 10 Nov 2016 14:01:07 -0600 Subject: [PATCH 167/180] Fix for broken libelfs that can't handle translate-in-place on Elf_Data. --- elf/src/Elf_X.C | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index 260ce42d2e..28d8f508bf 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -889,21 +889,31 @@ void Elf_X_Data::d_align(unsigned int input) } void Elf_X_Data::xlatetom(unsigned int encode) { + Elf_Data tmp; + memcpy(&tmp, data, sizeof(Elf_Data)); + tmp.d_buf = malloc(tmp.d_size); if(is64) { - elf64_xlatetom(data, data, encode); + elf64_xlatetom(&tmp, data, encode); } else { - elf32_xlatetom(data, data, encode); + elf32_xlatetom(&tmp, data, encode); } + memcpy(data->d_buf, tmp.d_buf, tmp.d_size); + free(tmp.d_buf); } void Elf_X_Data::xlatetof(unsigned int encode) { + Elf_Data tmp; + memcpy(&tmp, data, sizeof(Elf_Data)); + tmp.d_buf = malloc(tmp.d_size); if(is64) { - elf64_xlatetof(data, data, encode); + elf64_xlatetof(&tmp, data, encode); } else { - elf32_xlatetof(data, data, encode); + elf32_xlatetof(&tmp, data, encode); } + memcpy(data->d_buf, tmp.d_buf, tmp.d_size); + free(tmp.d_buf); } // Data Interface From 80a6d8e554699c5f389a30d129c8c688eb16726e Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 10 Nov 2016 15:30:43 -0600 Subject: [PATCH 168/180] Safeguard against infinite loop --- symtabAPI/src/LineInformation.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index dc32a8a332..8dd3b7a038 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -106,7 +106,7 @@ bool LineInformation::getSourceLines(Offset addressInRange, ++num_queries; const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); const_iterator end_addr_valid = impl_t::upper_bound(addressInRange ); - while(start_addr_valid != end_addr_valid) + while(start_addr_valid != end_addr_valid && start_addr_valid != end()) { if(*(*start_addr_valid) == addressInRange) { From f32ccea88e27cb0944b8ed791351789727b33c9d Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 10 Nov 2016 14:01:07 -0600 Subject: [PATCH 169/180] Fix for broken libelfs that can't handle translate-in-place on Elf_Data. --- elf/src/Elf_X.C | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index 260ce42d2e..28d8f508bf 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -889,21 +889,31 @@ void Elf_X_Data::d_align(unsigned int input) } void Elf_X_Data::xlatetom(unsigned int encode) { + Elf_Data tmp; + memcpy(&tmp, data, sizeof(Elf_Data)); + tmp.d_buf = malloc(tmp.d_size); if(is64) { - elf64_xlatetom(data, data, encode); + elf64_xlatetom(&tmp, data, encode); } else { - elf32_xlatetom(data, data, encode); + elf32_xlatetom(&tmp, data, encode); } + memcpy(data->d_buf, tmp.d_buf, tmp.d_size); + free(tmp.d_buf); } void Elf_X_Data::xlatetof(unsigned int encode) { + Elf_Data tmp; + memcpy(&tmp, data, sizeof(Elf_Data)); + tmp.d_buf = malloc(tmp.d_size); if(is64) { - elf64_xlatetof(data, data, encode); + elf64_xlatetof(&tmp, data, encode); } else { - elf32_xlatetof(data, data, encode); + elf32_xlatetof(&tmp, data, encode); } + memcpy(data->d_buf, tmp.d_buf, tmp.d_size); + free(tmp.d_buf); } // Data Interface From ee0baf4769bc1b52ec839a05631654b27724f0ba Mon Sep 17 00:00:00 2001 From: Bill Williams Date: Thu, 10 Nov 2016 15:30:43 -0600 Subject: [PATCH 170/180] Safeguard against infinite loop --- symtabAPI/src/LineInformation.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index dc32a8a332..8dd3b7a038 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -106,7 +106,7 @@ bool LineInformation::getSourceLines(Offset addressInRange, ++num_queries; const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); const_iterator end_addr_valid = impl_t::upper_bound(addressInRange ); - while(start_addr_valid != end_addr_valid) + while(start_addr_valid != end_addr_valid && start_addr_valid != end()) { if(*(*start_addr_valid) == addressInRange) { From 245207d345f4af56733dd39274276dd2185fe4f2 Mon Sep 17 00:00:00 2001 From: Rafael Stahl Date: Sun, 25 Sep 2016 21:05:11 +0200 Subject: [PATCH 171/180] Determine the architecture of an ELF by looking at the file header instead of the compiled architecture --- common/h/SymReader.h | 1 + elf/h/Elf_X.h | 3 +++ elf/src/Elf_X.C | 33 ++++++++++++++++++++++++++++++++ parseAPI/src/SymLiteCodeSource.C | 32 ++----------------------------- parseAPI/src/SymtabCodeSource.C | 32 ++----------------------------- symlite/h/SymLite-elf.h | 1 + symlite/src/SymLite-elf.C | 5 +++++ symtabAPI/h/Symtab.h | 6 ++++-- symtabAPI/h/SymtabReader.h | 1 + symtabAPI/src/Object-elf.C | 33 ++------------------------------ symtabAPI/src/Object-elf.h | 2 +- symtabAPI/src/Object.h | 2 +- symtabAPI/src/Symtab.C | 7 ++++++- symtabAPI/src/SymtabReader.C | 5 +++++ 14 files changed, 67 insertions(+), 96 deletions(-) diff --git a/common/h/SymReader.h b/common/h/SymReader.h index c4d46677df..dbf7e9ea45 100644 --- a/common/h/SymReader.h +++ b/common/h/SymReader.h @@ -91,6 +91,7 @@ class COMMON_EXPORT SymReader virtual unsigned getAddressWidth() = 0; virtual bool getABIVersion(int &major, int &minor) const = 0; virtual bool isBigEndianDataEncoding() const = 0; + virtual Architecture getArchitecture() const = 0; virtual unsigned numSegments() = 0; virtual bool getSegment(unsigned num, SymSegment ®) = 0; diff --git a/elf/h/Elf_X.h b/elf/h/Elf_X.h index f4e74a0baa..6882f40ea8 100644 --- a/elf/h/Elf_X.h +++ b/elf/h/Elf_X.h @@ -36,6 +36,7 @@ #include #include #include "util.h" +#include "dyn_regs.h" namespace Dyninst { @@ -117,6 +118,8 @@ class DYNELF_EXPORT Elf_X { bool findDebugFile(std::string origfilename, std::string &output_name, char* &output_buffer, unsigned long &output_buffer_size); + Dyninst::Architecture getArch() const; + protected: Elf *elf; Elf32_Ehdr *ehdr32; diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index 260ce42d2e..cdaafa85a5 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -1742,6 +1742,39 @@ bool Elf_X::findDebugFile(std::string origfilename, string &output_name, char* & return false; } +// Add definitions that may not be in all elf.h files +#if !defined(EM_K10M) +#define EM_K10M 180 +#endif +#if !defined(EM_L10M) +#define EM_L10M 181 +#endif +#if !defined(EM_AARCH64) +#define EM_AARCH64 183 +#endif +Dyninst::Architecture Elf_X::getArch() const +{ + switch(e_machine()) + { + case EM_PPC: + return Dyninst::Arch_ppc32; + case EM_PPC64: + return Dyninst::Arch_ppc64; + case EM_386: + return Dyninst::Arch_x86; + case EM_X86_64: + case EM_K10M: + case EM_L10M: + return Dyninst::Arch_x86_64; + case EM_ARM: + return Dyninst::Arch_aarch32; + case EM_AARCH64: + return Dyninst::Arch_aarch64; + default: + return Dyninst::Arch_none; + } +} + // ------------------------------------------------------------------------ // Class Elf_X_Nhdr simulates the Elf(32|64)_Nhdr structure. Elf_X_Nhdr::Elf_X_Nhdr() diff --git a/parseAPI/src/SymLiteCodeSource.C b/parseAPI/src/SymLiteCodeSource.C index 2023313f73..9a92a99db1 100644 --- a/parseAPI/src/SymLiteCodeSource.C +++ b/parseAPI/src/SymLiteCodeSource.C @@ -141,21 +141,7 @@ SymReaderCodeRegion::getAddressWidth() const Architecture SymReaderCodeRegion::getArch() const { -#if defined(arch_power) - if(getAddressWidth() == 8) - return Arch_ppc64; - else - return Arch_ppc32; -#elif defined(arch_x86) || defined(arch_x86_64) - if(getAddressWidth() == 8) - return Arch_x86_64; - else - return Arch_x86; -#elif defined(arch_aarch64) - return Arch_aarch64; -#else - return Arch_none; -#endif + return _symtab->getArchitecture(); } bool @@ -473,21 +459,7 @@ SymReaderCodeSource::getAddressWidth() const Architecture SymReaderCodeSource::getArch() const { -#if defined(arch_power) - if(getAddressWidth() == 8) - return Arch_ppc64; - else - return Arch_ppc32; -#elif defined(arch_x86) || defined(arch_x86_64) - if(getAddressWidth() == 8) - return Arch_x86_64; - else - return Arch_x86; -#elif defined(arch_aarch64) - return Arch_aarch64; -#else - return Arch_none; -#endif + return _symtab->getArchitecture(); } bool diff --git a/parseAPI/src/SymtabCodeSource.C b/parseAPI/src/SymtabCodeSource.C index 39552784f2..09d93be795 100644 --- a/parseAPI/src/SymtabCodeSource.C +++ b/parseAPI/src/SymtabCodeSource.C @@ -146,21 +146,7 @@ SymtabCodeRegion::getAddressWidth() const Architecture SymtabCodeRegion::getArch() const { -#if defined(arch_power) - if(getAddressWidth() == 8) - return Arch_ppc64; - else - return Arch_ppc32; -#elif defined(arch_x86) || defined(arch_x86_64) - if(getAddressWidth() == 8) - return Arch_x86_64; - else - return Arch_x86; -#elif defined(arch_aarch64) - return Arch_aarch64; -#else - return Arch_none; -#endif + return _symtab->getArchitecture(); } bool @@ -653,21 +639,7 @@ SymtabCodeSource::getAddressWidth() const Architecture SymtabCodeSource::getArch() const { -#if defined(arch_power) - if(getAddressWidth() == 8) - return Arch_ppc64; - else - return Arch_ppc32; -#elif defined(arch_x86) || defined(arch_x86_64) - if(getAddressWidth() == 8) - return Arch_x86_64; - else - return Arch_x86; -#elif defined(arch_aarch64) - return Arch_aarch64; -#else - return Arch_none; -#endif + return _symtab->getArchitecture(); } bool diff --git a/symlite/h/SymLite-elf.h b/symlite/h/SymLite-elf.h index 6836396adc..104bbc61fe 100644 --- a/symlite/h/SymLite-elf.h +++ b/symlite/h/SymLite-elf.h @@ -88,6 +88,7 @@ class SYMLITE_EXPORT SymElf : public Dyninst::SymReader virtual unsigned getAddressWidth(); virtual bool getABIVersion(int &major, int &minor) const; virtual bool isBigEndianDataEncoding() const; + virtual Architecture getArchitecture() const; virtual unsigned long getSymbolSize(const Symbol_t &sym); virtual Section_t getSectionByName(std::string name); diff --git a/symlite/src/SymLite-elf.C b/symlite/src/SymLite-elf.C index 3fa1007939..83d6c0abb1 100644 --- a/symlite/src/SymLite-elf.C +++ b/symlite/src/SymLite-elf.C @@ -311,6 +311,11 @@ bool SymElf::isBigEndianDataEncoding() const return (elf->e_endian() != 0); } +Architecture SymElf::getArchitecture() const +{ + return elf->getArch(); +} + unsigned long SymElf::getSymbolSize(const Symbol_t &sym) { GET_SYMBOL(sym, shdr, symbol, name, idx); diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index c30eb8cc84..cad95014ab 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -235,7 +235,7 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, bool isExec() const; bool isStripped(); ObjectType getObjectType() const; - Dyninst::Architecture getArchitecture(); + Dyninst::Architecture getArchitecture() const; bool isCode(const Offset where) const; bool isData(const Offset where) const; bool isValidOffset(const Offset where) const; @@ -604,7 +604,9 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, //Don't use obj_private, use getObject() instead. public: Object *getObject(); - ModRangeLookup* mod_lookup(); + const Object *getObject() const; + ModRangeLookup* mod_lookup(); + private: Object *obj_private; diff --git a/symtabAPI/h/SymtabReader.h b/symtabAPI/h/SymtabReader.h index 1dbe0f5118..7674cc417e 100644 --- a/symtabAPI/h/SymtabReader.h +++ b/symtabAPI/h/SymtabReader.h @@ -80,6 +80,7 @@ class SYMTAB_EXPORT SymtabReader : public SymReader { virtual unsigned getAddressWidth(); virtual bool isBigEndianDataEncoding() const; virtual bool getABIVersion(int &major, int &minor) const; + virtual Architecture getArchitecture() const; virtual unsigned numSegments(); virtual bool getSegment(unsigned num, SymSegment &seg); diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index fabc0cbdf8..01c747fd17 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -5118,38 +5118,9 @@ bool Object::getTruncateLinePaths() return truncateLineFilenames; } -// Add definitions that may not be in all elf.h files -#if !defined(EM_K10M) -#define EM_K10M 180 -#endif -#if !defined(EM_L10M) -#define EM_L10M 181 -#endif -#if !defined(EM_AARCH64) -#define EM_AARCH64 183 -#endif - -Dyninst::Architecture Object::getArch() +Dyninst::Architecture Object::getArch() const { - switch(elfHdr->e_machine()) - { - case EM_PPC: - return Dyninst::Arch_ppc32; - case EM_PPC64: - return Dyninst::Arch_ppc64; - case EM_386: - return Dyninst::Arch_x86; - case EM_X86_64: - case EM_K10M: - case EM_L10M: - return Dyninst::Arch_x86_64; - case EM_ARM: - return Dyninst::Arch_aarch32; - case EM_AARCH64: - return Dyninst::Arch_aarch64; - default: - return Dyninst::Arch_none; - } + return elfHdr->getArch(); } bool Object::getABIVersion(int &major, int &minor) const diff --git a/symtabAPI/src/Object-elf.h b/symtabAPI/src/Object-elf.h index 5d27b4a3be..76d2e06eae 100644 --- a/symtabAPI/src/Object-elf.h +++ b/symtabAPI/src/Object-elf.h @@ -349,7 +349,7 @@ class Object; return false; } - Dyninst::Architecture getArch(); + Dyninst::Architecture getArch() const; bool isBigEndianDataEncoding() const; bool getABIVersion(int &major, int &minor) const; bool is_offset_in_plt(Offset offset) const; diff --git a/symtabAPI/src/Object.h b/symtabAPI/src/Object.h index c4cf5a9350..5d9e4fb823 100644 --- a/symtabAPI/src/Object.h +++ b/symtabAPI/src/Object.h @@ -128,7 +128,7 @@ class AObject { Dyninst::MachRegisterVal & /*reg_result*/, Dyninst::SymtabAPI::MemRegReader * /*reader*/) {return false;} - SYMTAB_EXPORT virtual Dyninst::Architecture getArch() { return Arch_none; }; + SYMTAB_EXPORT virtual Dyninst::Architecture getArch() const { return Arch_none; }; SYMTAB_EXPORT const std::string findModuleForSym(Symbol *sym); SYMTAB_EXPORT void setModuleForOffset(Offset sym_off, std::string module); SYMTAB_EXPORT void clearSymsToMods(); diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index b17870a327..a87483bd5b 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -2847,7 +2847,7 @@ SYMTAB_EXPORT ObjectType Symtab::getObjectType() const return object_type_; } -SYMTAB_EXPORT Dyninst::Architecture Symtab::getArchitecture() +SYMTAB_EXPORT Dyninst::Architecture Symtab::getArchitecture() const { return getObject()->getArch(); } @@ -3300,6 +3300,11 @@ Object *Symtab::getObject() //return obj_private; } +const Object *Symtab::getObject() const +{ + return obj_private; +} + void Symtab::parseTypesNow() { if (isTypeInfoValid_) diff --git a/symtabAPI/src/SymtabReader.C b/symtabAPI/src/SymtabReader.C index 06a7c5630c..d0ce45aabd 100644 --- a/symtabAPI/src/SymtabReader.C +++ b/symtabAPI/src/SymtabReader.C @@ -141,6 +141,11 @@ bool SymtabReader::isBigEndianDataEncoding() const return symtab->isBigEndianDataEncoding(); } +Architecture SymtabReader::getArchitecture() const +{ + return symtab->getArchitecture(); +} + unsigned SymtabReader::numSegments() { buildSegments(); From 6c10d55c94984a057a07de8283d35b35213a91f5 Mon Sep 17 00:00:00 2001 From: Rafael Stahl Date: Sun, 25 Sep 2016 21:26:37 +0200 Subject: [PATCH 172/180] Object-nt: Fix member function constness --- symtabAPI/src/Object-nt.C | 2 +- symtabAPI/src/Object-nt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index 9d0231396c..0896b33c14 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -2351,7 +2351,7 @@ void Object::insertPrereqLibrary(std::string lib) getRegionPermissions() == RP_RWX); } -Dyninst::Architecture Object::getArch() +Dyninst::Architecture Object::getArch() const { return Dyninst::Arch_x86; } diff --git a/symtabAPI/src/Object-nt.h b/symtabAPI/src/Object-nt.h index 09b706db4d..e3a5ff18da 100644 --- a/symtabAPI/src/Object-nt.h +++ b/symtabAPI/src/Object-nt.h @@ -202,7 +202,7 @@ class Object : public AObject SYMTAB_EXPORT const char *interpreter_name() const { return NULL; } SYMTAB_EXPORT dyn_hash_map &getLineInfo(); SYMTAB_EXPORT void parseTypeInfo(); - SYMTAB_EXPORT virtual Dyninst::Architecture getArch(); + SYMTAB_EXPORT virtual Dyninst::Architecture getArch() const; SYMTAB_EXPORT void ParseGlobalSymbol(PSYMBOL_INFO pSymInfo); SYMTAB_EXPORT const std::vector &getPossibleMains() const { return possible_mains; } SYMTAB_EXPORT void getModuleLanguageInfo(dyn_hash_map *mod_langs); From 3335ea9706962bd1e895e96daf751b1b21e5bba1 Mon Sep 17 00:00:00 2001 From: Rafael Stahl Date: Wed, 28 Sep 2016 16:33:29 +0200 Subject: [PATCH 173/180] Object-nt: implement getArch --- symtabAPI/src/Object-nt.C | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/symtabAPI/src/Object-nt.C b/symtabAPI/src/Object-nt.C index 0896b33c14..61e8131117 100644 --- a/symtabAPI/src/Object-nt.C +++ b/symtabAPI/src/Object-nt.C @@ -2353,7 +2353,15 @@ void Object::insertPrereqLibrary(std::string lib) Dyninst::Architecture Object::getArch() const { - return Dyninst::Arch_x86; + switch (peHdr->FileHeader.Machine) + { + case IMAGE_FILE_MACHINE_I386: + return Dyninst::Arch_x86; + case IMAGE_FILE_MACHINE_AMD64: + return Dyninst::Arch_x86_64; + default: + return Dyninst::Arch_none; + } } /* From 2c1b67eca9ad00addbbbd346b57dddbf51040052 Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Fri, 11 Nov 2016 13:41:04 -0600 Subject: [PATCH 174/180] Only stop slicing when encoutering missing instruction semantics on ARM --- parseAPI/src/JumpTablePred.C | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/parseAPI/src/JumpTablePred.C b/parseAPI/src/JumpTablePred.C index e82b14c493..8abab4c22d 100644 --- a/parseAPI/src/JumpTablePred.C +++ b/parseAPI/src/JumpTablePred.C @@ -211,7 +211,9 @@ bool JumpTablePred::addNodeCallback(AssignmentPtr ap, set &visi */ if (!expandRet.second || expandRet.first == NULL) { - unknownInstruction = true; + if (ap && ap->block() && ap->block()->obj()->cs()->getArch() == Arch_aarch64) { + unknownInstruction = true; + } return true; } From d8edc10eafe935b80ebfd95e7c01e7791add50c5 Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Fri, 11 Nov 2016 14:24:47 -0600 Subject: [PATCH 175/180] Do not output missing semantics to stderr --- dataflowAPI/src/SymbolicExpansion.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataflowAPI/src/SymbolicExpansion.C b/dataflowAPI/src/SymbolicExpansion.C index 607e09e82c..2070fc881e 100644 --- a/dataflowAPI/src/SymbolicExpansion.C +++ b/dataflowAPI/src/SymbolicExpansion.C @@ -89,7 +89,7 @@ bool SymbolicExpansion::expandAarch64(SgAsmInstruction *rose_insn, BaseSemantics try { cpu->processInstruction(insn); } catch (rose::BinaryAnalysis::InstructionSemantics2::BaseSemantics::Exception &e) { - fprintf(stderr, "Instruction processing threw exception for instruction: %s\n", insn_dump.c_str()); + // fprintf(stderr, "Instruction processing threw exception for instruction: %s\n", insn_dump.c_str()); } return false; From a64a47497024bc8b8eab5b1adaf046dbae535efc Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Sun, 13 Nov 2016 19:39:46 -0600 Subject: [PATCH 176/180] Remove fprintf output --- dataflowAPI/rose/semantics/DispatcherARM64.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataflowAPI/rose/semantics/DispatcherARM64.C b/dataflowAPI/rose/semantics/DispatcherARM64.C index 7c44b2de47..70285d8485 100644 --- a/dataflowAPI/rose/semantics/DispatcherARM64.C +++ b/dataflowAPI/rose/semantics/DispatcherARM64.C @@ -1318,7 +1318,7 @@ namespace rose { } break; case MemOp_LOAD: { - fprintf(stderr, "xxx %d %d\n", 0x8 << EXTR(30, 31), EXTR(30, 31)); +// fprintf(stderr, "xxx %d %d\n", 0x8 << EXTR(30, 31), EXTR(30, 31)); data = d->readMemory(address, 0x8 << EXTR(30, 31)); if ((EXTR(23, 23) == 1)) { From d43f8e46f4f9fb3c92db8e75d18c93ceb4503240 Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Sat, 19 Nov 2016 17:28:41 -0600 Subject: [PATCH 177/180] Clean parsing log messages --- dataflowAPI/h/SymEval.h | 6 +++--- parseAPI/src/IndirectAnalyzer.C | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/dataflowAPI/h/SymEval.h b/dataflowAPI/h/SymEval.h index 17511d62fd..81aece3114 100644 --- a/dataflowAPI/h/SymEval.h +++ b/dataflowAPI/h/SymEval.h @@ -96,7 +96,7 @@ struct Variable { } friend std::ostream& operator<<(std::ostream& stream, const Variable& c) { - stream << c.format() << std::endl; + stream << c.format(); return stream; } @@ -129,7 +129,7 @@ struct Constant { } friend std::ostream& operator<<(std::ostream& stream, const Constant& c) { - stream << c.format() << std::endl; + stream << c.format(); return stream; } @@ -290,7 +290,7 @@ DATAFLOW_EXPORT const std::string format() const { }; friend std::ostream& operator<<(std::ostream& stream, const ROSEOperation& c) { - stream << c.format() << std::endl; + stream << c.format(); return stream; } diff --git a/parseAPI/src/IndirectAnalyzer.C b/parseAPI/src/IndirectAnalyzer.C index fa5beb10d0..b633415af1 100644 --- a/parseAPI/src/IndirectAnalyzer.C +++ b/parseAPI/src/IndirectAnalyzer.C @@ -17,8 +17,8 @@ using namespace Dyninst::InstructionAPI; bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector >& outEdges) { -// if (block->last() == 0xfa10) dyn_debug_parsing = 1; else dyn_debug_parsing = 0; - +// if (block->last() == 0x47947) dyn_debug_parsing = 1; else dyn_debug_parsing = 0; +// if (block->last() == 0x52460) dyn_debug_parsing=1; else dyn_debug_parsing=0; parsing_printf("Apply indirect control flow analysis at %lx\n", block->last()); parsing_printf("Looking for thunk\n"); @@ -120,10 +120,10 @@ void IndirectControlFlowAnalyzer::FindAllThunks() { parsing_printf("%s[%d]: failed to get pointer to instruction by offset\n",FILE__, __LINE__); return; } - parsing_printf("Looking for thunk in block [%lx,%lx).", b->start(), b->end()); InstructionDecoder dec(buf, b->end() - b->start(), b->obj()->cs()->getArch()); InsnAdapter::IA_IAPI block(dec, b->start(), b->obj() , b->region(), b->obj()->cs(), b); - while (block.getAddr() < b->end()) { + Address cur = b->start(); + while (cur < b->end()) { if (block.getInstruction()->getCategory() == c_CallInsn && block.isThunk()) { bool valid; Address addr; @@ -144,7 +144,8 @@ void IndirectControlFlowAnalyzer::FindAllThunks() { parsing_printf("\tfind thunk at %lx, storing value %lx to %s\n", block.getAddr(), t.value , t.reg.name().c_str()); } } - block.advance(); + cur += block.getInstruction()->size(); + if (cur < b->end()) block.advance(); } } } From d811f19e4b94abeb7877d569e768a110ab606298 Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Sun, 20 Nov 2016 20:49:25 -0600 Subject: [PATCH 178/180] 1. An indirect jump may be shared by several different jump tables. Add value set representations so that we can union jump targets from different tables. 2. Separate input absloc from absloc at the current address, as they may have different values --- parseAPI/src/BoundFactCalculator.C | 2 +- parseAPI/src/BoundFactData.C | 93 +++++++++++++++------- parseAPI/src/BoundFactData.h | 13 +++- parseAPI/src/IndirectASTVisitor.C | 109 +++++++++++++++++++++++++- parseAPI/src/IndirectASTVisitor.h | 4 +- parseAPI/src/JumpTablePred.C | 121 ++++------------------------- 6 files changed, 205 insertions(+), 137 deletions(-) diff --git a/parseAPI/src/BoundFactCalculator.C b/parseAPI/src/BoundFactCalculator.C index abd00cbf19..6dc8655bf0 100644 --- a/parseAPI/src/BoundFactCalculator.C +++ b/parseAPI/src/BoundFactCalculator.C @@ -392,7 +392,7 @@ BoundFact* BoundFactsCalculator::Meet(Node::Ptr curNode) { first = false; if (newCopy) newFact = prevFact; else newFact = new BoundFact(*prevFact); } else { - newFact->Meet(*prevFact); + newFact->Meet(*prevFact, func->entry()); if (newCopy) delete prevFact; } } diff --git a/parseAPI/src/BoundFactData.C b/parseAPI/src/BoundFactData.C index 622b0bb7dc..95dacd8bf4 100644 --- a/parseAPI/src/BoundFactData.C +++ b/parseAPI/src/BoundFactData.C @@ -360,6 +360,7 @@ BoundValue::BoundValue(int64_t val): targetBase(0), tableReadSize(0), multiply(1), + values(NULL), isInverted(false), isSubReadContent(false), isZeroExtend(false) {} @@ -369,6 +370,7 @@ BoundValue::BoundValue(const StridedInterval &si): targetBase(0), tableReadSize(0), multiply(1), + values(NULL), isInverted(false), isSubReadContent(false), isZeroExtend(false){} @@ -378,6 +380,7 @@ BoundValue::BoundValue(): targetBase(0), tableReadSize(0), multiply(1), + values(NULL), isInverted(false), isSubReadContent(false), isZeroExtend(false) {} @@ -387,21 +390,37 @@ BoundValue::BoundValue(const BoundValue & bv): targetBase(bv.targetBase), tableReadSize(bv.tableReadSize), multiply(bv.multiply), + values(NULL), isInverted(bv.isInverted), isSubReadContent(bv.isSubReadContent), isZeroExtend(bv.isZeroExtend) { + if (bv.values != NULL) { + values = new set(*(bv.values)); + } } +BoundValue::~BoundValue() { + if (values != NULL) { + delete values; + values = NULL; + } +} bool BoundValue::operator == (const BoundValue &bv) const { - return (interval == bv.interval) && - (targetBase == bv.targetBase) && - (tableReadSize == bv.tableReadSize) && - (multiply == bv.multiply) && - (isInverted == bv.isInverted) && - (isSubReadContent == bv.isSubReadContent) && - (isZeroExtend == bv.isZeroExtend); + if (values == NULL && bv.values == NULL) { + return (interval == bv.interval) && + (targetBase == bv.targetBase) && + (tableReadSize == bv.tableReadSize) && + (multiply == bv.multiply) && + (isInverted == bv.isInverted) && + (isSubReadContent == bv.isSubReadContent) && + (isZeroExtend == bv.isZeroExtend); + } else if (values != NULL && bv.values != NULL) { + return *values == *bv.values; + } else { + return false; + } } bool BoundValue::operator != (const BoundValue &bv) const { @@ -417,18 +436,32 @@ BoundValue & BoundValue::operator = (const BoundValue &bv) { isInverted = bv.isInverted; isSubReadContent = bv.isSubReadContent; isZeroExtend = bv.isZeroExtend; + if (values != NULL) { + delete values; + values = NULL; + } + if (bv.values != NULL) { + values = new set(*bv.values); + } return *this; } void BoundValue::Print() { - parsing_printf("Interval %s, ", interval.format().c_str() ); - parsing_printf("targetBase %lx, ",targetBase); - parsing_printf("tableReadSize %d, ", tableReadSize); - parsing_printf("multiply %d, ", multiply); - parsing_printf("isInverted %d, ", isInverted); - parsing_printf("isSubReadContent %d, ", isSubReadContent); - parsing_printf("isZeroExtend %d\n", isZeroExtend); + if (values == NULL) { + parsing_printf("Interval %s, ", interval.format().c_str() ); + parsing_printf("targetBase %lx, ",targetBase); + parsing_printf("tableReadSize %d, ", tableReadSize); + parsing_printf("multiply %d, ", multiply); + parsing_printf("isInverted %d, ", isInverted); + parsing_printf("isSubReadContent %d, ", isSubReadContent); + parsing_printf("isZeroExtend %d\n", isZeroExtend); + } else { + parsing_printf("Values:"); + for (auto vit = values->begin(); vit != values->end(); ++vit) + parsing_printf(" %x", *vit); + parsing_printf("\n"); + } } @@ -471,7 +504,7 @@ void BoundValue::DeleteElementFromInterval(int64_t val) { interval.DeleteElement(val); } -void BoundValue::Join(BoundValue &bv) { +void BoundValue::Join(BoundValue &bv, Block *b) { // If one is a table read and the other is a constant, // assume that the constant appears in the table read. if (tableReadSize > 0 && bv.interval.stride == 0) { @@ -481,6 +514,21 @@ void BoundValue::Join(BoundValue &bv) { *this = bv; return; } + if (tableReadSize > 0 && bv.tableReadSize > 0) { + // If both paths represent a table read, + // it could be a case where multiple jump tables share + // an indirect jump. + // Example: 0x47947 at libc-2.17.so + set left, right; + bool leftRet, rightRet; + leftRet = PerformTableRead(*this, left, b->obj()->cs()); + rightRet = PerformTableRead(bv, right, b->obj()->cs()); + if (leftRet && rightRet) { + left.insert(right.begin(), right.end()); + values = new set (left); + return; + } + } if (tableReadSize != bv.tableReadSize) { // Unless boths are table reads, we stop trakcing // how the read is used. @@ -694,7 +742,7 @@ void BoundValue::MemoryRead(Block* b, int readSize) { } } -void BoundFact::Meet(BoundFact &bf) { +void BoundFact::Meet(BoundFact &bf, Block* b) { for (auto fit = fact.begin(); fit != fact.end();) { BoundValue *val2 = bf.GetBound(fit->first); // if ast fit->first cannot be found in bf, @@ -702,7 +750,7 @@ void BoundFact::Meet(BoundFact &bf) { // Anything joins top becomes top if (val2 != NULL) { BoundValue *val1 = fit->second; - val1->Join(*val2); + val1->Join(*val2, b); ++fit; } else { auto toErase = fit; @@ -1538,17 +1586,6 @@ AST::Ptr BoundFact::GetAlias(const AST::Ptr ast) { } void BoundFact::TrackAlias(AST::Ptr expr, AST::Ptr outAST, bool findBound) { - // This definition should kill all existing aliases - // involving outAST, as outAST is assigned to a new value - parsing_printf("\tTracking alias for %s = %s\n", outAST->format().c_str(), expr->format().c_str()); - for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ) { - if (ContainAnAST(ait->second , outAST)) { - auto e = ait; - ++ait; - aliasMap.erase(e); - } else ++ait; - } - expr = SubstituteAnAST(expr, aliasMap); bool find = false; for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ++ait) { diff --git a/parseAPI/src/BoundFactData.h b/parseAPI/src/BoundFactData.h index 7e8a33c1a3..a4aa286b67 100644 --- a/parseAPI/src/BoundFactData.h +++ b/parseAPI/src/BoundFactData.h @@ -81,6 +81,7 @@ struct BoundValue { // Otherwise, tableReadSize reprenents the number bytes of the access int tableReadSize; int multiply; + std::set * values; bool isInverted; bool isSubReadContent; bool isZeroExtend; @@ -89,6 +90,7 @@ struct BoundValue { BoundValue(); BoundValue(const BoundValue & bv); BoundValue& operator = (const BoundValue &bv); + ~BoundValue(); bool operator< (const BoundValue &bv) const { return interval < bv.interval; } bool operator== (const BoundValue &bv) const; bool operator!= (const BoundValue &bv) const; @@ -97,7 +99,7 @@ struct BoundValue { void SetToBottom(); void IntersectInterval(StridedInterval &si); void DeleteElementFromInterval(int64_t val); - void Join(BoundValue &bv); + void Join(BoundValue &bv, ParseAPI::Block* b); void ClearTableCheck(); void Add(const BoundValue &rhs); void And(const BoundValue &rhs); @@ -152,6 +154,13 @@ struct BoundFact { vector relation; + // We need to track aliases of each register and memory locations. + // The left hand side represents an abstract location at the current address + // and the right hand side represents an AST of input absloc locations. + // eax at the current location can be different from eax at the input absloc location + // + // Register abstract location with address 0 represents an absloc at the current address + // Register abstract location with address 1 represents an input absloc typedef std::map AliasMap; AliasMap aliasMap; @@ -210,7 +219,7 @@ struct BoundFact { BoundValue* GetBound(const AST::Ptr ast); BoundValue* GetBound(const AST* ast); AST::Ptr GetAlias(const AST::Ptr ast); - void Meet(BoundFact &bf); + void Meet(BoundFact &bf, ParseAPI::Block* b); bool ConditionalJumpBound(InstructionAPI::Instruction::Ptr insn, EdgeTypeEnum type); diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index e2486e343f..eafbf7a33f 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -5,6 +5,11 @@ #include using namespace Dyninst::ParseAPI; +#define SIGNEX_64_32 0xffffffff00000000LL +#define SIGNEX_64_16 0xffffffffffff0000LL +#define SIGNEX_64_8 0xffffffffffffff00LL +#define SIGNEX_32_16 0xffff0000 +#define SIGNEX_32_8 0xffffff00 Address PCValue(Address cur, size_t insnSize, Architecture a) { switch (a) { @@ -288,7 +293,7 @@ AST::Ptr BoundCalcVisitor::visit(DataflowAPI::RoseAST *ast) { case ROSEOperation::ifOp: if (IsResultBounded(ast->child(1)) && IsResultBounded(ast->child(2))) { BoundValue *val = new BoundValue(*GetResultBound(ast->child(1))); - val->Join(*GetResultBound(ast->child(2))); + val->Join(*GetResultBound(ast->child(2)), block); if (*val != BoundValue::top) bound.insert(make_pair(ast, val)); } @@ -404,6 +409,12 @@ AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap) { for (unsigned i = 0 ; i < totalChildren; ++i) { ast->setChild(i, SubstituteAnAST(ast->child(i), aliasMap)); } + if (ast->getID() == AST::V_VariableAST) { + // If this variable is not in the aliasMap yet, + // this variable is from the input. + VariableAST::Ptr varAST = boost::static_pointer_cast(ast); + return VariableAST::create(Variable(varAST->val().reg, 1)); + } return ast; } @@ -497,3 +508,99 @@ AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) { } return AST::Ptr(); } + +bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource *cs) { + + Address tableBase = (Address)target.interval.low; + Address tableLastEntry = (Address)target.interval.high; + int addressWidth = cs->getAddressWidth(); + if (addressWidth == 4) { + tableBase &= 0xffffffff; + tableLastEntry &= 0xffffffff; + } + +#if defined(os_windows) + tableBase -= cs->loadAddress(); + tableLastEntry -= cs->loadAddress(); +#endif + + if (!cs->isCode(tableBase) && !cs->isData(tableBase)) { + parsing_printf("\ttableBase 0x%lx invalid, returning false\n", tableBase); + parsing_printf("Not jump table format!\n"); + return false; + } + if (!cs->isReadOnly(tableBase)) { + parsing_printf("\ttableBase 0x%lx not read only, returning false\n", tableBase); + parsing_printf("Not jump table format!\n"); + return false; + } + + + for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += target.interval.stride) { + if (!cs->isCode(tableEntry) && !cs->isData(tableEntry)) continue; + if (!cs->isReadOnly(tableEntry)) continue; + int targetAddress = 0; + if (target.tableReadSize > 0) { + switch (target.tableReadSize) { + case 8: + targetAddress = *(const uint64_t *) cs->getPtrToInstruction(tableEntry); + break; + case 4: + targetAddress = *(const uint32_t *) cs->getPtrToInstruction(tableEntry); + if (target.isZeroExtend) break; + if ((addressWidth == 8) && (targetAddress & 0x80000000)) { + targetAddress |= SIGNEX_64_32; + } + break; + case 2: + targetAddress = *(const uint16_t *) cs->getPtrToInstruction(tableEntry); + if (target.isZeroExtend) break; + if ((addressWidth == 8) && (targetAddress & 0x8000)) { + targetAddress |= SIGNEX_64_16; + } + if ((addressWidth == 4) && (targetAddress & 0x8000)) { + targetAddress |= SIGNEX_32_16; + } + + break; + case 1: + targetAddress = *(const uint8_t *) cs->getPtrToInstruction(tableEntry); + if (target.isZeroExtend) break; + if ((addressWidth == 8) && (targetAddress & 0x80)) { + targetAddress |= SIGNEX_64_8; + } + if ((addressWidth == 4) && (targetAddress & 0x80)) { + targetAddress |= SIGNEX_32_8; + } + + break; + + default: + parsing_printf("Invalid memory read size %d\n", target.tableReadSize); + return false; + } + targetAddress *= target.multiply; + if (target.targetBase != 0) { + if (target.isSubReadContent) + targetAddress = target.targetBase - targetAddress; + else + targetAddress += target.targetBase; + + } +#if defined(os_windows) + targetAddress -= cs->loadAddress(); +#endif + } else targetAddress = tableEntry; + + if (addressWidth == 4) targetAddress &= 0xffffffff; + parsing_printf("Jumping to target %lx,", targetAddress); + if (cs->isCode(targetAddress)) { + // Jump tables may contain may repetitious entries. + // We only want to create one edge for disctinct each jump target. + jumpTargets.insert(targetAddress); + } + // If the jump target is resolved to be a constant, + if (target.interval.stride == 0) break; + } + return true; +} diff --git a/parseAPI/src/IndirectASTVisitor.h b/parseAPI/src/IndirectASTVisitor.h index e5393be8e5..02268f4975 100644 --- a/parseAPI/src/IndirectASTVisitor.h +++ b/parseAPI/src/IndirectASTVisitor.h @@ -5,7 +5,7 @@ #include "DynAST.h" #include "SymEval.h" - +#include "CodeSource.h" #include "BoundFactData.h" using namespace std; @@ -17,6 +17,8 @@ AST::Ptr SimplifyAnAST(AST::Ptr ast, Address addr); AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap); AST::Ptr DeepCopyAnAST(AST::Ptr ast); bool ContainAnAST(AST::Ptr root, AST::Ptr check); +bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource*); + // On x86 and x86-64, the value of PC is post-instruction, // which is the current address plus the length of the instruction. diff --git a/parseAPI/src/JumpTablePred.C b/parseAPI/src/JumpTablePred.C index 90413bc577..44cfd6845c 100644 --- a/parseAPI/src/JumpTablePred.C +++ b/parseAPI/src/JumpTablePred.C @@ -17,14 +17,10 @@ using namespace Dyninst; using namespace Dyninst::DataflowAPI; using namespace Dyninst::ParseAPI; using namespace Dyninst::InstructionAPI; -#define SIGNEX_64_32 0xffffffff00000000LL -#define SIGNEX_64_16 0xffffffffffff0000LL -#define SIGNEX_64_8 0xffffffffffffff00LL -#define SIGNEX_32_16 0xffff0000 -#define SIGNEX_32_8 0xffffff00 - // Assume the table contain less than this many entries. #define MAX_TABLE_ENTRY 1000000 + + static void BuildEdgesAux(SliceNode::Ptr srcNode, ParseAPI::Block* curBlock, map > &targetMap, @@ -260,106 +256,19 @@ bool JumpTablePred::addNodeCallback(AssignmentPtr ap, set &visi } bool JumpTablePred::FillInOutEdges(BoundValue &target, vector >& outEdges) { - set

jumpTargets; - outEdges.clear(); - Address tableBase = (Address)target.interval.low; - Address tableLastEntry = (Address)target.interval.high; - int addressWidth = block->obj()->cs()->getAddressWidth(); - if (addressWidth == 4) { - tableBase &= 0xffffffff; - tableLastEntry &= 0xffffffff; + if (target.values != NULL) { + outEdges.clear(); + for (auto tit = target.values->begin(); tit != target.values->end(); ++tit) { + outEdges.push_back(make_pair(*tit, INDIRECT)); + } + return true; } - -#if defined(os_windows) - tableBase -= block->obj()->cs()->loadAddress(); - tableLastEntry -= block->obj()->cs()->loadAddress(); -#endif - - parsing_printf("The final target bound fact:\n"); - target.Print(); - if (!block->obj()->cs()->isCode(tableBase) && !block->obj()->cs()->isData(tableBase)) { - parsing_printf("\ttableBase 0x%lx invalid, returning false\n", tableBase); - jumpTableFormat = false; - parsing_printf("Not jump table format!\n"); + set jumpTargets; + if (!PerformTableRead(target, jumpTargets, block->obj()->cs())) { + jumpTableFormat = false; return false; } - if (!block->obj()->cs()->isReadOnly(tableBase)) { - parsing_printf("\ttableBase 0x%lx not read only, returning false\n", tableBase); - jumpTableFormat = false; - parsing_printf("Not jump table format!\n"); - return false; - } - - - for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += target.interval.stride) { - if (!block->obj()->cs()->isCode(tableEntry) && !block->obj()->cs()->isData(tableEntry)) continue; - if (!block->obj()->cs()->isReadOnly(tableEntry)) continue; - int targetAddress = 0; - if (target.tableReadSize > 0) { - switch (target.tableReadSize) { - case 8: - targetAddress = *(const uint64_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - break; - case 4: - targetAddress = *(const uint32_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - if (target.isZeroExtend) break; - if ((addressWidth == 8) && (targetAddress & 0x80000000)) { - targetAddress |= SIGNEX_64_32; - } - break; - case 2: - targetAddress = *(const uint16_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - if (target.isZeroExtend) break; - if ((addressWidth == 8) && (targetAddress & 0x8000)) { - targetAddress |= SIGNEX_64_16; - } - if ((addressWidth == 4) && (targetAddress & 0x8000)) { - targetAddress |= SIGNEX_32_16; - } - - break; - case 1: - targetAddress = *(const uint8_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - if (target.isZeroExtend) break; - if ((addressWidth == 8) && (targetAddress & 0x80)) { - targetAddress |= SIGNEX_64_8; - } - if ((addressWidth == 4) && (targetAddress & 0x80)) { - targetAddress |= SIGNEX_32_8; - } - - break; - - default: - parsing_printf("Invalid memory read size %d\n", target.tableReadSize); - return false; - } - targetAddress *= target.multiply; - if (target.targetBase != 0) { - if (target.isSubReadContent) - targetAddress = target.targetBase - targetAddress; - else - targetAddress += target.targetBase; - - } -#if defined(os_windows) - targetAddress -= block->obj()->cs()->loadAddress(); -#endif - } else targetAddress = tableEntry; - - if (addressWidth == 4) targetAddress &= 0xffffffff; - parsing_printf("Jumping to target %lx,", targetAddress); - if (block->obj()->cs()->isCode(targetAddress)) { - // Jump tables may contain may repetitious entries. - // We only want to create one edge for disctinct each jump target. - jumpTargets.insert(targetAddress); - parsing_printf(" is code.\n" ); - } else { - parsing_printf(" not code.\n"); - } - // If the jump target is resolved to be a constant, - if (target.interval.stride == 0) break; - } + outEdges.clear(); for (auto tit = jumpTargets.begin(); tit != jumpTargets.end(); ++tit) { outEdges.push_back(make_pair(*tit, INDIRECT)); } @@ -381,7 +290,11 @@ bool JumpTablePred::IsJumpTable(GraphPtr slice, BoundValue *tarBoundValue = bf->GetBound(ip); if (tarBoundValue != NULL) { target = *(tarBoundValue); - uint64_t s = target.interval.size(); + uint64_t s; + if (target.values == NULL) + s = target.interval.size(); + else + s = target.values->size(); if (s > 0 && s <= MAX_TABLE_ENTRY) return true; } AST::Ptr ipExp = bf->GetAlias(ip); From c0f9eb28bf5c3d6c95923ba99a78da581212714f Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Sun, 20 Nov 2016 22:03:43 -0600 Subject: [PATCH 179/180] Address calculation should use 64-bit integers.. --- parseAPI/src/BoundFactData.C | 8 ++++---- parseAPI/src/BoundFactData.h | 2 +- parseAPI/src/IndirectASTVisitor.C | 4 ++-- parseAPI/src/IndirectASTVisitor.h | 2 +- parseAPI/src/IndirectAnalyzer.C | 3 +-- parseAPI/src/JumpTablePred.C | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/parseAPI/src/BoundFactData.C b/parseAPI/src/BoundFactData.C index 95dacd8bf4..b9646574b1 100644 --- a/parseAPI/src/BoundFactData.C +++ b/parseAPI/src/BoundFactData.C @@ -396,7 +396,7 @@ BoundValue::BoundValue(const BoundValue & bv): isZeroExtend(bv.isZeroExtend) { if (bv.values != NULL) { - values = new set(*(bv.values)); + values = new set(*(bv.values)); } } @@ -441,7 +441,7 @@ BoundValue & BoundValue::operator = (const BoundValue &bv) { values = NULL; } if (bv.values != NULL) { - values = new set(*bv.values); + values = new set(*bv.values); } return *this; @@ -519,13 +519,13 @@ void BoundValue::Join(BoundValue &bv, Block *b) { // it could be a case where multiple jump tables share // an indirect jump. // Example: 0x47947 at libc-2.17.so - set left, right; + set left, right; bool leftRet, rightRet; leftRet = PerformTableRead(*this, left, b->obj()->cs()); rightRet = PerformTableRead(bv, right, b->obj()->cs()); if (leftRet && rightRet) { left.insert(right.begin(), right.end()); - values = new set (left); + values = new set (left); return; } } diff --git a/parseAPI/src/BoundFactData.h b/parseAPI/src/BoundFactData.h index a4aa286b67..9aa9c458ef 100644 --- a/parseAPI/src/BoundFactData.h +++ b/parseAPI/src/BoundFactData.h @@ -81,7 +81,7 @@ struct BoundValue { // Otherwise, tableReadSize reprenents the number bytes of the access int tableReadSize; int multiply; - std::set * values; + std::set * values; bool isInverted; bool isSubReadContent; bool isZeroExtend; diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index eafbf7a33f..b74a3e9c11 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -509,7 +509,7 @@ AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) { return AST::Ptr(); } -bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource *cs) { +bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource *cs) { Address tableBase = (Address)target.interval.low; Address tableLastEntry = (Address)target.interval.high; @@ -539,7 +539,7 @@ bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource *cs for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += target.interval.stride) { if (!cs->isCode(tableEntry) && !cs->isData(tableEntry)) continue; if (!cs->isReadOnly(tableEntry)) continue; - int targetAddress = 0; + int64_t targetAddress = 0; if (target.tableReadSize > 0) { switch (target.tableReadSize) { case 8: diff --git a/parseAPI/src/IndirectASTVisitor.h b/parseAPI/src/IndirectASTVisitor.h index 02268f4975..d07a20984d 100644 --- a/parseAPI/src/IndirectASTVisitor.h +++ b/parseAPI/src/IndirectASTVisitor.h @@ -17,7 +17,7 @@ AST::Ptr SimplifyAnAST(AST::Ptr ast, Address addr); AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap); AST::Ptr DeepCopyAnAST(AST::Ptr ast); bool ContainAnAST(AST::Ptr root, AST::Ptr check); -bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource*); +bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource*); // On x86 and x86-64, the value of PC is post-instruction, diff --git a/parseAPI/src/IndirectAnalyzer.C b/parseAPI/src/IndirectAnalyzer.C index b633415af1..33a144db07 100644 --- a/parseAPI/src/IndirectAnalyzer.C +++ b/parseAPI/src/IndirectAnalyzer.C @@ -17,8 +17,7 @@ using namespace Dyninst::InstructionAPI; bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector >& outEdges) { -// if (block->last() == 0x47947) dyn_debug_parsing = 1; else dyn_debug_parsing = 0; -// if (block->last() == 0x52460) dyn_debug_parsing=1; else dyn_debug_parsing=0; +// if (block->last() == 0x3ed4e2c437) dyn_debug_parsing=1; else dyn_debug_parsing=0; parsing_printf("Apply indirect control flow analysis at %lx\n", block->last()); parsing_printf("Looking for thunk\n"); diff --git a/parseAPI/src/JumpTablePred.C b/parseAPI/src/JumpTablePred.C index 44cfd6845c..54e4d27215 100644 --- a/parseAPI/src/JumpTablePred.C +++ b/parseAPI/src/JumpTablePred.C @@ -263,7 +263,7 @@ bool JumpTablePred::FillInOutEdges(BoundValue &target, } return true; } - set jumpTargets; + set jumpTargets; if (!PerformTableRead(target, jumpTargets, block->obj()->cs())) { jumpTableFormat = false; return false; From dd1b12e7dfab293bd0c13995241e61b4e4406386 Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Mon, 21 Nov 2016 09:39:13 -0600 Subject: [PATCH 180/180] On x86, and instruction would generate an zf assignment that looks like an assignment generated from a cmp instruction. The zf assignment from and needs special handling from a zf assignment from cmp. --- parseAPI/src/BoundFactData.C | 30 ++++++++++++------------------ parseAPI/src/IndirectASTVisitor.C | 2 +- parseAPI/src/IndirectAnalyzer.C | 2 +- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/parseAPI/src/BoundFactData.C b/parseAPI/src/BoundFactData.C index b9646574b1..05b0c980cb 100644 --- a/parseAPI/src/BoundFactData.C +++ b/parseAPI/src/BoundFactData.C @@ -1381,23 +1381,8 @@ void BoundFact::SetPredicate(Assignment::Ptr assign,std::pair ex AST::Ptr simplifiedAST = expandRet.first; parsing_printf("\t\t semanic expansions: %s\n", simplifiedAST->format().c_str()); - ComparisonVisitor cv; - expandRet.first->accept(&cv); - pred.e1 = cv.subtrahend; - pred.e2 = cv.minuend; - pred.id = id; - if (pred.e1 != AST::Ptr() && pred.e2 != AST::Ptr()) { - return; - } - + // Special handling of test and and instructions on x86 switch (id) { - case e_cmp: - case e_sub: { - // The effect of the subtraction can only - // be evaluated when there is a conditional jump - // after it. Currently, we do not know anything. - break; - } case e_test: { if (simplifiedAST->getID() == AST::V_RoseAST) { RoseAST::Ptr rootRoseAST = boost::static_pointer_cast(simplifiedAST); @@ -1456,8 +1441,17 @@ void BoundFact::SetPredicate(Assignment::Ptr assign,std::pair ex break; } default: - parsing_printf("Not tracking this instruction that sets flags: %s\n", insn->format().c_str()); - pred.valid = false; + break; + } + + + ComparisonVisitor cv; + expandRet.first->accept(&cv); + pred.e1 = cv.subtrahend; + pred.e2 = cv.minuend; + pred.id = id; + if (pred.e1 == AST::Ptr() || pred.e2 == AST::Ptr()) { + pred.valid = false; } } diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index b74a3e9c11..88c9469336 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -233,7 +233,7 @@ AST::Ptr BoundCalcVisitor::visit(DataflowAPI::RoseAST *ast) { else val = new BoundValue(BoundValue::top); if (IsResultBounded(ast->child(1))) - val->And(GetResultBound(ast->child(1))->interval); + val->And(*GetResultBound(ast->child(1))); else val->And(StridedInterval::top); // the result of an AND operation should not be diff --git a/parseAPI/src/IndirectAnalyzer.C b/parseAPI/src/IndirectAnalyzer.C index 33a144db07..501a04773c 100644 --- a/parseAPI/src/IndirectAnalyzer.C +++ b/parseAPI/src/IndirectAnalyzer.C @@ -17,7 +17,7 @@ using namespace Dyninst::InstructionAPI; bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector >& outEdges) { -// if (block->last() == 0x3ed4e2c437) dyn_debug_parsing=1; else dyn_debug_parsing=0; +// if (block->last() == 0x3ed4f33e9e) dyn_debug_parsing=1; else dyn_debug_parsing=0; parsing_printf("Apply indirect control flow analysis at %lx\n", block->last()); parsing_printf("Looking for thunk\n");