diff --git a/binaryfile.cpp b/binaryfile.cpp index 23efb9308..616f906f6 100644 --- a/binaryfile.cpp +++ b/binaryfile.cpp @@ -385,10 +385,11 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, // Collect symbol names for (auto &Symbol : TheELF.symbols(SymtabShdr)) { Symbols.push_back({ - Symbol.getName(StrtabContent).get(), - Symbol.st_value, - Symbol.st_size - }); + Symbol.getName(StrtabContent).get(), + Symbol.st_value, + Symbol.st_size, + Symbol.getType() == ELF::STT_FUNC + }); } } diff --git a/binaryfile.h b/binaryfile.h index 18405ed41..f2205abd9 100644 --- a/binaryfile.h +++ b/binaryfile.h @@ -73,6 +73,7 @@ struct SymbolInfo { llvm::StringRef Name; uint64_t Address; uint64_t Size; + bool IsFunction; bool operator<(const SymbolInfo &Other) const { return Address < Other.Address; diff --git a/codegenerator.cpp b/codegenerator.cpp index 4be537339..39bcfdf25 100644 --- a/codegenerator.cpp +++ b/codegenerator.cpp @@ -89,7 +89,8 @@ CodeGenerator::CodeGenerator(BinaryFile &Binary, bool EnableOSRA, bool DetectFunctionBoundaries, bool EnableLinking, - bool ExternalCSVs) : + bool ExternalCSVs, + bool UseDebugSymbols) : TargetArchitecture(Target), Context(getGlobalContext()), TheModule((new Module("top", Context))), @@ -99,7 +100,8 @@ CodeGenerator::CodeGenerator(BinaryFile &Binary, EnableOSRA(EnableOSRA), DetectFunctionBoundaries(DetectFunctionBoundaries), EnableLinking(EnableLinking), - ExternalCSVs(ExternalCSVs) + ExternalCSVs(ExternalCSVs), + UseDebugSymbols(UseDebugSymbols) { OriginalInstrMDKind = Context.getMDKindID("oi"); PTCInstrMDKind = Context.getMDKindID("pi"); @@ -964,7 +966,9 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { if (DetectFunctionBoundaries) { legacy::FunctionPassManager FPM(&*TheModule); - FPM.add(new FunctionBoundariesDetectionPass(&JumpTargets, "")); + FPM.add(new FunctionBoundariesDetectionPass(&JumpTargets, + "", + UseDebugSymbols)); FPM.run(*MainFunction); } diff --git a/codegenerator.h b/codegenerator.h index 0460fd91a..164fac26b 100644 --- a/codegenerator.h +++ b/codegenerator.h @@ -75,7 +75,8 @@ public: bool EnableOSRA, bool DetectFunctionBoundaries, bool EnableLinking, - bool ExternalCSVs); + bool ExternalCSVs, + bool UseDebugSymbols); ~CodeGenerator(); @@ -132,6 +133,7 @@ private: bool DetectFunctionBoundaries; bool EnableLinking; bool ExternalCSVs; + bool UseDebugSymbols; }; #endif // _CODEGENERATOR_H diff --git a/docs/GeneratedIRReference.rst b/docs/GeneratedIRReference.rst index c75d27e93..07b6f70cc 100644 --- a/docs/GeneratedIRReference.rst +++ b/docs/GeneratedIRReference.rst @@ -55,7 +55,7 @@ And it has been translated as follows: .. code-block:: sh - ./revamb --no-link --functions-boundaries --use-sections --debug-info ll example example.ll + ./revamb --no-link --functions-boundaries --use-debug-symbols --debug-info ll example example.ll Global variables ================ diff --git a/docs/RevambUsage.rst b/docs/RevambUsage.rst index 166579696..32ce11fc4 100644 --- a/docs/RevambUsage.rst +++ b/docs/RevambUsage.rst @@ -75,10 +75,11 @@ are described: `internal`. This degrades performances of the produced binary sensibly but makes debugging the generated code easier. -:``-S``, ``--use-sections``: If they are available, ELF sections are employed to - identify executable code. This options is useful to - evaluate `revamb` ignoring the code identification - issue. +:``-S``, ``--use-debug-symbols``: If they are available, ELF sections and + function symbols are employed to identify + executable code and function boundaries. This + options is useful evaluate `revamb` ignoring + the code issue. :``-b``, ``--bb-summary``: Output path for the CSV containing statistics about the translated basic blocks. This option is deprecated in favor of using `revamb-dump` and will diff --git a/functionboundariesdetection.cpp b/functionboundariesdetection.cpp index 99f53f907..750fe5547 100644 --- a/functionboundariesdetection.cpp +++ b/functionboundariesdetection.cpp @@ -54,7 +54,11 @@ static RegisterPass X("fbdp", class FunctionBoundariesDetectionImpl { public: FunctionBoundariesDetectionImpl(Function &F, - JumpTargetManager *JTM) : F(F), JTM(JTM) { } + JumpTargetManager *JTM, + bool UseDebugSymbols) : + F(F), + JTM(JTM), + UseDebugSymbols(UseDebugSymbols) { } map> run(); @@ -72,7 +76,8 @@ private: Callee = 1, GlobalData = 2, InCode = 4, - SkippingJump = 8 + SkippingJump = 8, + FunctionSymbol = 16 }; class CFEPRelation { @@ -175,6 +180,7 @@ private: private: Function &F; JumpTargetManager *JTM; + bool UseDebugSymbols; std::map FunctionCalls; std::map> CallPredecessors; @@ -357,6 +363,13 @@ void FBD::collectInitialCFEPSet() { Insert = true; } + if (UseDebugSymbols) { + if (JT.hasReason(JTReason::FunctionSymbol)) { + registerCFEP(CFEPHead, FunctionSymbol); + Insert = true; + } + } + if (Insert) CFEPWorkList.insert(CFEPHead); } @@ -463,7 +476,7 @@ void FBD::filterCFEPs() { // Keep a CFEP only if its address is taken, it's a callee or all the // paths leading there are skipping jumps - bool Keep = C.hasReason(Callee); + bool Keep = C.hasReason(Callee) || C.hasReason(FunctionSymbol); bool AddressTaken = C.hasReason(GlobalData) || C.hasReason(InCode); if (!Keep && AddressTaken) { @@ -492,6 +505,7 @@ void FBD::filterCFEPs() { << " GlobalData? " << C.hasReason(GlobalData) << " InCode? " << C.hasReason(InCode) << " SkippingJump? " << C.hasReason(SkippingJump) + << " FunctionSymbol?" << C.hasReason(FunctionSymbol) << "\n"; }); It++; @@ -631,7 +645,7 @@ std::string FBD::CFEPRelation::describe() const { } bool FBDP::runOnFunction(Function &F) { - FBD Impl(F, JTM); + FBD Impl(F, JTM, UseDebugSymbols); Functions = Impl.run(); serialize(); return false; diff --git a/functionboundariesdetection.h b/functionboundariesdetection.h index 94604bb28..2236ceb8f 100644 --- a/functionboundariesdetection.h +++ b/functionboundariesdetection.h @@ -25,7 +25,8 @@ public: public: FunctionBoundariesDetectionPass() : llvm::FunctionPass(ID), JTM(nullptr) { } FunctionBoundariesDetectionPass(JumpTargetManager *JTM, - std::string SerializePath) : + std::string SerializePath, + bool UseDebugSymbols) : llvm::FunctionPass(ID), JTM(JTM), SerializePath(SerializePath) { } void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { @@ -40,6 +41,7 @@ private: private: JumpTargetManager *JTM; std::string SerializePath; + bool UseDebugSymbols; std::map> Functions; }; diff --git a/jumptargetmanager.cpp b/jumptargetmanager.cpp index 7d792c7b6..31df3d1da 100644 --- a/jumptargetmanager.cpp +++ b/jumptargetmanager.cpp @@ -516,6 +516,11 @@ std::string JumpTargetManager::nameForAddress(uint64_t Address) const { } void JumpTargetManager::harvestGlobalData() { + // Register symbols + for (const SymbolInfo &Symbol : Binary.symbols()) + if (Symbol.IsFunction) + registerJT(Symbol.Address, JTReason::FunctionSymbol); + // Register landing pads, if available // TODO: should register them in UnusedCodePointers? for (uint64_t LandingPad : Binary.landingPads()) diff --git a/main.cpp b/main.cpp index bffd1dd5e..b3acebf30 100644 --- a/main.cpp +++ b/main.cpp @@ -51,11 +51,11 @@ struct ProgramParameters { const char *LinkingInfoPath; const char *CoveragePath; const char *BBSummaryPath; - int NoOSRA; - int UseSections; - int DetectFunctionsBoundaries; - int NoLink; - int External; + bool NoOSRA; + bool UseDebugSymbols; + bool DetectFunctionsBoundaries; + bool NoLink; + bool External; bool PrintStats; uint64_t BaseAddress; }; @@ -228,8 +228,8 @@ static int parseArgs(int Argc, const char *Argv[], "do not link the output to QEMU helpers."), OPT_BOOLEAN('E', "external", &Parameters->External, "set CSVs linkage to external, useful for debugging purposes."), - OPT_BOOLEAN('S', "use-sections", &Parameters->UseSections, - "use section informations, if available."), + OPT_BOOLEAN('S', "use-debug-symbols", &Parameters->UseDebugSymbols, + "use section and symbol function informations, if available."), OPT_STRING('b', "bb-summary", &Parameters->BBSummaryPath, "destination path for the CSV containing the statistics about " @@ -329,7 +329,7 @@ int main(int argc, const char *argv[]) { return EXIT_FAILURE; BinaryFile TheBinary(Parameters.InputPath, - Parameters.UseSections, + Parameters.UseDebugSymbols, Parameters.BaseAddress); findFiles(TheBinary.architecture().name()); @@ -354,7 +354,8 @@ int main(int argc, const char *argv[]) { !Parameters.NoOSRA, Parameters.DetectFunctionsBoundaries, !Parameters.NoLink, - Parameters.External); + Parameters.External, + Parameters.UseDebugSymbols); Generator.translate(Parameters.EntryPointAddress); diff --git a/revamb.h b/revamb.h index 13160efb1..8af15ed99 100644 --- a/revamb.h +++ b/revamb.h @@ -104,7 +104,8 @@ enum Values { SumJump = 256, ///< Obtained from the "sumjump" heuristic LoadAddress = 512, ///< A load has been performed from this address ReturnAddress = 1024, ///< Obtained as the fallthrough of a function call - LastReason = ReturnAddress + FunctionSymbol = 2048, ///< Obtained from a function symbol + LastReason = FunctionSymbol }; inline const char *getName(Values Reason) { @@ -131,6 +132,8 @@ inline const char *getName(Values Reason) { return "LoadAddress"; case ReturnAddress: return "ReturnAddress"; + case FunctionSymbol: + return "FunctionSymbol"; } abort(); @@ -159,6 +162,8 @@ inline Values fromName(llvm::StringRef ReasonName) { return LoadAddress; else if (ReasonName == "ReturnAddress") return ReturnAddress; + else if (ReasonName == "FunctionSymbol") + return FunctionSymbol; else abort(); } diff --git a/tests/Analysis/AnalysisTests.cmake b/tests/Analysis/AnalysisTests.cmake index 51cf497d2..5fe736b66 100644 --- a/tests/Analysis/AnalysisTests.cmake +++ b/tests/Analysis/AnalysisTests.cmake @@ -77,7 +77,7 @@ foreach(ARCH ${SUPPORTED_ARCHITECTURES}) # Translate the compiled binary add_test(NAME translate-${TEST_NAME}-${ARCH} - COMMAND $ --functions-boundaries --use-sections -g ll "${BINARY}" "${BINARY}.ll") + COMMAND $ --functions-boundaries --use-debug-symbols -g ll "${BINARY}" "${BINARY}.ll") set_tests_properties(translate-${TEST_NAME}-${ARCH} PROPERTIES LABELS "analysis;translate;${TEST_NAME}-${ARCH}") diff --git a/tests/Runtime/RuntimeTests.cmake b/tests/Runtime/RuntimeTests.cmake index f89e8fdd8..d392d5a96 100644 --- a/tests/Runtime/RuntimeTests.cmake +++ b/tests/Runtime/RuntimeTests.cmake @@ -67,7 +67,7 @@ foreach(TEST_NAME ${TESTS}) # Translate the dynamic native version add_test(NAME translate-native-dynamic-${TEST_NAME} - COMMAND sh -c "${CMAKE_BINARY_DIR}/translate $ -- --functions-boundaries --use-sections -g ll") + COMMAND sh -c "${CMAKE_BINARY_DIR}/translate $ -- --functions-boundaries --use-debug-symbols -g ll") set_tests_properties(translate-native-dynamic-${TEST_NAME} PROPERTIES LABELS "runtime;translate-native-dynamic;${TEST_NAME}") @@ -127,13 +127,13 @@ foreach(ARCH ${SUPPORTED_ARCHITECTURES}) # Translate the compiled binary add_test(NAME translate-${TEST_NAME}-${ARCH} - COMMAND sh -c "${CMAKE_BINARY_DIR}/translate ${BINARY} -- --functions-boundaries --use-sections -g ll") + COMMAND sh -c "${CMAKE_BINARY_DIR}/translate ${BINARY} -- --functions-boundaries --use-debug-symbols -g ll") set_tests_properties(translate-${TEST_NAME}-${ARCH} PROPERTIES LABELS "runtime;translate;${TEST_NAME};${ARCH}") # Translate the compiled binary with function isolation add_test(NAME translate-with-isolation-${TEST_NAME}-${ARCH} - COMMAND sh -c "cp ${BINARY} ${BINARY}.isolated-functions && ${CMAKE_BINARY_DIR}/translate -i ${BINARY}.isolated-functions -- --functions-boundaries --use-sections -g ll") + COMMAND sh -c "cp ${BINARY} ${BINARY}.isolated-functions && ${CMAKE_BINARY_DIR}/translate -i ${BINARY}.isolated-functions -- --functions-boundaries --use-debug-symbols -g ll") set_tests_properties(translate-${TEST_NAME}-${ARCH} PROPERTIES LABELS "runtime;translate-with-isolation;${TEST_NAME};${ARCH}") diff --git a/translate b/translate index 5b16ffd79..ff846507b 100755 --- a/translate +++ b/translate @@ -132,7 +132,7 @@ fi if [ "$SKIP" -eq 0 ]; then REVAMB_LOG="$LL.log" CSV="$LL.ll.li.csv" - "$REVAMB" -g ll --debug jtcount,osrjts --use-sections $BASE $EXTRA_OPTIONS "$INPUT" "$LL.ll" "$@" |& tee "$REVAMB_LOG" + "$REVAMB" -g ll --debug jtcount,osrjts --use-debug-symbols $BASE $EXTRA_OPTIONS "$INPUT" "$LL.ll" "$@" |& tee "$REVAMB_LOG" fi if [ "$ISOLATE" -eq 1 ]; then