diff --git a/include/base/SMPProgram.h b/include/base/SMPProgram.h index aa14f3cc237388d4f6880ee4c55fd05a7fa289d0..fbece3c40a7a1895eb16603c1097adc2eb88a4f6 100644 --- a/include/base/SMPProgram.h +++ b/include/base/SMPProgram.h @@ -142,6 +142,7 @@ public: void AnalyzeData(void); // Analyze static data in the program. void Analyze(ProfilerInformation* pi, FILE *AnnotFile, FILE *InfoAnnotFile); // Analyze all functions in the program void EmitDataAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile); // Emit annotations for global data + bool EmitProgramSPARKAda(void); // return false if error occurs void EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile); // Emit annotations for all functions bool IsInstAddrStillInFunction(STARS_ea_t InstAddr, STARS_ea_t &FirstAddrInFunc); // is InstAddr still an SMPInstr inside an SMPFunction object? (not orphaned, not dead-code-removed) bool IsChunkUnshared(STARS_ea_t ChunkAddr, STARS_ea_t FuncHeadStart, STARS_ea_t FuncHeadEnd); // Does chunk at ChunkAddr belong exclusively to FuncHead? diff --git a/src/base/SMPFunction.cpp b/src/base/SMPFunction.cpp index e67aff23143c629ee13cae00f86ebb1934e55d61..b11cbf64ff2bff2dbaa081a84460ddec83bc67dd 100644 --- a/src/base/SMPFunction.cpp +++ b/src/base/SMPFunction.cpp @@ -3976,7 +3976,7 @@ void SMPFunction::AdvancedAnalysis(void) { } // end if not shared chunks else { // has shared chunks; still want to compute stack frame info #ifdef SMP_DEBUG_FUNC - SMP_msg(" %s has shared chunks \n", this->GetFuncName()); + SMP_msg("INFO: %s has shared chunks \n", this->GetFuncName()); #endif // Figure out the stack frame and related info. this->SetStackFrameInfo(); @@ -8644,7 +8644,6 @@ void SMPFunction::MarkFunctionSafe() { // Emit SPARK Ada translation of function void SMPFunction::EmitFuncSPARKAda(void) { -#if ZST_EMIT_SPARK_ADA_TRANSLATION if (this->IsLinkerStub()) { return; } @@ -8654,9 +8653,82 @@ void SMPFunction::EmitFuncSPARKAda(void) { } #endif - FILE *OutFile = global_STARS_program->GetSPARKSourceFile(); + FILE *BodyFile = global_STARS_program->GetSPARKSourceFile(); FILE *HeaderFile = global_STARS_program->GetSPARKHeaderFile(); - + size_t ByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); + + // Emit beginning of function body. + SMP_fprintf(BodyFile, "procedure %s\nis\n", this->GetFuncName()); + SMP_fprintf(BodyFile, "\tra0 : Unsigned8 := X86.ReadMem8(X86.RSP);\n"); + for (unsigned short i = 1; i < ByteWidth; ++i) { + SMP_fprintf(BodyFile, "\tra%u : Unsigned8 := X86.ReadMem8(X86.RSP + %u);\n", i, i); + } + SMP_fprintf(BodyFile, "\n"); + + // Emit procedure specification. + SMP_fprintf(HeaderFile, "procedure %s with\n", this->GetFuncName()); + SMP_fprintf(HeaderFile, "\tGlobal => (In_Out => (X86.Memory, X86.Exit_Called, X86.CarryFlag,\n"); + SMP_fprintf(HeaderFile, "\t\tX86.OverflowFlag, X86.SignFlag, X86.ZeroFlag,\n"); + // Form union of regs killed, LiveOut, and LiveIn + std::set<STARSOpndTypePtr, LessOp> RegInOutSet(this->KillSet); + // RegInOutSet.insert(this->LiveOutSet.begin(), this->LiveOutSet.end()); // must be subset of KillSet already + RegInOutSet.insert(this->RPOBlocks.at(0)->GetFirstLiveIn(), this->RPOBlocks.at(0)->GetLastLiveIn()); + std::set<STARSOpndTypePtr, LessOp>::iterator RegIter = RegInOutSet.begin(); + size_t RegCount = 0; // How many reg operands did we leave in the RegInOutSet. After this count comes memory operands. + // NOTE: When erase() was called on the memops after the regs, a seg fault happened on some random memop even though + // erase() succeeded on previous memops and the end of the set had not been reached. Quick fix is to do less erase() + // and let RegCount be our sentinel. + while (RegIter != RegInOutSet.end()) { + bool FlagsReg = (*RegIter)->MatchesReg(MD_FLAGS_REG); + bool RegOp = (*RegIter)->IsRegOp(); + if (RegOp && (!FlagsReg)) { // Keep non-flags regs in set + ++RegIter; + ++RegCount; + } + else { // delete non-regs and flags reg from the set + // Use C++98 erase() method, which does not return a new iterator + if ((RegOp && FlagsReg) || (0 == RegCount)) { // have not seen first reg, or we are looking at flags reg + std::set<STARSOpndTypePtr, LessOp>::iterator NextRegIter(RegIter); + ++NextRegIter; + RegInOutSet.erase(RegIter); + RegIter = NextRegIter; + } + else if (0 < RegCount) { // Have processed regs and now we have moved past them in the set. + break; + } + } + } + + size_t OutCount = 0; + for (RegIter = RegInOutSet.begin(); RegIter != RegInOutSet.end(); ++RegIter) { + if (0 == OutCount) { // first line does not need another newline + SMP_fprintf(HeaderFile, "\t\t"); + } + else if (0 == (OutCount % 4)) { // print 4 regs per line + SMP_fprintf(HeaderFile, "\n\t\t"); + } + ++OutCount; + if (OutCount == RegCount) { // last reg needs no comma after it, but must close inner parentheses + SMP_fprintf(HeaderFile, " X86.%s),\n", MDGetRegName(*RegIter)); + break; + } + else { + SMP_fprintf(HeaderFile, " X86.%s, ", MDGetRegName(*RegIter)); + } + } + SMP_fprintf(HeaderFile, "\t\tInput => (X86.StackAddressSize, X86.FS, X86.GS)),\n"); + SMP_fprintf(HeaderFile, "\tPre => (X86.RSP > 16#FFFFFFFF00000000# and X86.RSP < 16#FFFFFFFFFFFFFF00#),\n"); + SMP_fprintf(HeaderFile, "\tPost => (X86.RSP = (X86.RSP'Old + 8)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old) = X86.Memory'Old(X86.RSP'Old)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 1) = X86.Memory'Old(X86.RSP'Old + 1)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 2) = X86.Memory'Old(X86.RSP'Old + 2)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 3) = X86.Memory'Old(X86.RSP'Old + 3)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 4) = X86.Memory'Old(X86.RSP'Old + 4)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 5) = X86.Memory'Old(X86.RSP'Old + 5)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 6) = X86.Memory'Old(X86.RSP'Old + 6)) and\n"); + SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 7) = X86.Memory'Old(X86.RSP'Old + 7));\n"); + + // Iterate through all instructions and emit SPARK Ada for each. list<SMPInstr *>::iterator InstIter = this->Instrs.begin(); #if SMP_USE_SSA_FNOP_MARKER ++InstIter; // skip marker instruction @@ -8664,10 +8736,10 @@ void SMPFunction::EmitFuncSPARKAda(void) { while (InstIter != this->Instrs.end()) { SMPInstr *CurrInst = (*InstIter); STARS_ea_t InstAddr = CurrInst->GetAddr(); - CurrInst->EmitSPARKAda(OutFile); + CurrInst->EmitSPARKAda(BodyFile); ++InstIter; } // end while all instrs -#endif + return; } // end of SMPFunction::EmitFuncSPARKAda() diff --git a/src/base/SMPInstr.cpp b/src/base/SMPInstr.cpp index bda2b6054b4cdd8e6344f1063d681f55d64de536..ab2647e4b0c4a2fbe854fcdbd82112cd5b9cdb68 100644 --- a/src/base/SMPInstr.cpp +++ b/src/base/SMPInstr.cpp @@ -2672,7 +2672,7 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile) { // to the jump translation. NextAddr = InstAddr + (STARS_ea_t) this->GetSize(); PrintSPARKIndentTabs(OutFile); - SMP_fprintf(OutFile, " X86.WriteMem%d(Unsigned%d(X86.RSP - %d), %llx );\n", STARS_ISA_Bitwidth, STARS_ISA_Bitwidth, + SMP_fprintf(OutFile, " X86.WriteMem%d(Unsigned%d(X86.RSP - %d), 16\#%llx\# );\n", STARS_ISA_Bitwidth, STARS_ISA_Bitwidth, global_STARS_program->GetSTARS_ISA_Bytewidth(), (unsigned long long) NextAddr); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.RSP := X86.RSP - %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth()); @@ -2768,7 +2768,7 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile) { } NextAddr = InstAddr + (STARS_ea_t) this->GetSize(); PrintSPARKIndentTabs(OutFile); - SMP_fprintf(OutFile, " X86.WriteMem%d(Unsigned%d(X86.RSP - %d), %llu );\n", + SMP_fprintf(OutFile, " X86.WriteMem%d(Unsigned%d(X86.RSP - %d), 16\#%llx\# );\n", STARS_ISA_Bitwidth, STARS_ISA_Bitwidth, global_STARS_program->GetSTARS_ISA_Bytewidth(), (unsigned long long) NextAddr); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.RSP := X86.RSP - %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth()); diff --git a/src/base/SMPProgram.cpp b/src/base/SMPProgram.cpp index 4c2829394bf45ab986dfd495e3033462adbdc13f..9b9837e0ad68e2278afee999c0ccb2387c6decc9 100644 --- a/src/base/SMPProgram.cpp +++ b/src/base/SMPProgram.cpp @@ -39,6 +39,8 @@ #include <map> #include <vector> #include <algorithm> +#include <iostream> +#include <sstream> #include <cstdint> #include <cstring> @@ -776,6 +778,50 @@ void SMPProgram::EmitDataAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile) { return; } // SMPProgram::EmitDataAnnotations() +bool SMPProgram::EmitProgramSPARKAda(void) { + FILE *BodyFile = global_STARS_program->GetSPARKSourceFile(); // SPARK Ada *.adb implementation + FILE *SpecFile = global_STARS_program->GetSPARKHeaderFile(); // SPARK Ada *.ads specification + string RootName(global_STARS_program->GetRootFileName()); // original file name without path, e.g. foo.exe + + // Extract "foo" from "foo.exe" to get the Ada package name + string PackageName; + istringstream StreamRootName(RootName); + (void) std::getline(StreamRootName, PackageName, '.'); + if (PackageName.empty()) { + SMP_msg("ERROR: Could not extract an Ada package name from the root of file name %s\n", RootName.c_str()); + return false; + } + + // Emit the package body. + SMP_fprintf(BodyFile, "Package body %s\n", PackageName.c_str()); + SMP_fprintf(BodyFile, "with SPARK_Mode \nis\n\n"); + + // Emit the package specification. + SMP_fprintf(SpecFile, "with Interfaces;\nuse Interfaces;\nwith X86;\n\n"); + SMP_fprintf(SpecFile, "Package %s\n", PackageName.c_str()); + SMP_fprintf(SpecFile, "with SPARK_Mode \nis\n\n"); + SMP_fprintf(SpecFile, "\tsubtype Unsigned64 is X86.Unsigned64;\n"); + SMP_fprintf(SpecFile, "\tsubtype Unsigned32 is X86.Unsigned32;\n"); + SMP_fprintf(SpecFile, "\tsubtype Unsigned16 is X86.Unsigned16;\n"); + SMP_fprintf(SpecFile, "\tsubtype Unsigned8 is X86.Unsigned8;\n\n"); + + // Loop through all functions and emit annotations for each. + map<STARS_ea_t, SMPFunction *>::iterator FuncIter; + for (FuncIter = this->FuncMap.begin(); FuncIter != this->FuncMap.end(); ++FuncIter) { + SMPFunction *TempFunc = FuncIter->second; + if (TempFunc == NULL) continue; + if (TempFunc->HasReducibleControlFlow()) { + TempFunc->EmitFuncSPARKAda(); + } + } // end for all functions + + // Wrap up the package files. + SMP_fprintf(BodyFile, "\nend %s;\n", PackageName.c_str()); + SMP_fprintf(SpecFile, "\nend %s;\n", PackageName.c_str()); + + return true; +} // end of SMPProgram::EmitProgramSPARKAda() + // Emit all annotations for the program. void SMPProgram::EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile) { long TotalSafeBlocks = 0; // basic blocks with no unsafe writes @@ -795,12 +841,11 @@ void SMPProgram::EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile) { TempFunc->EmitAnnotations(AnnotFile, InfoAnnotFile); TotalSafeBlocks += TempFunc->GetSafeBlocks(); TotalUnsafeBlocks += TempFunc->GetUnsafeBlocks(); + } // end for all functions + #if ZST_EMIT_SPARK_ADA_TRANSLATION - if (TempFunc->HasReducibleControlFlow()) { - TempFunc->EmitFuncSPARKAda(); - } + (void) this->EmitProgramSPARKAda(); #endif - } // end for all functions EndTime = time(NULL); double TimeDiff = difftime(EndTime, StartTime); diff --git a/src/drivers/idapro/SMPStaticAnalyzer.cpp b/src/drivers/idapro/SMPStaticAnalyzer.cpp index a8c55b1cd3f483e3fe7565d79c5daef56c911748..6e3bf2ff4442370c1a7ee9291647e3d16f037f34 100644 --- a/src/drivers/idapro/SMPStaticAnalyzer.cpp +++ b/src/drivers/idapro/SMPStaticAnalyzer.cpp @@ -62,7 +62,7 @@ using namespace std; -#define SMP_DEBUG_DELAY 0 // for setting an early breakpoint +#define SMP_DEBUG_DELAY 1 // for setting an early breakpoint // Set to 1 for debugging output #define SMP_DEBUG 1