From 3603877f42bbb96b2fbbe2933321ce6233a0a0d3 Mon Sep 17 00:00:00 2001 From: nemerle Date: Fri, 7 Mar 2014 20:01:36 +0100 Subject: [PATCH] Qt5 command options processing --- CMakeLists.txt | 14 ++-- include/dcc.h | 6 +- include/symtab.h | 20 ++---- regression_tester.rb | 6 +- src/backend.cpp | 6 +- src/chklib.cpp | 1 - src/dcc.cpp | 150 ++++++++++++++++++------------------------- src/disassem.cpp | 2 +- src/frontend.cpp | 2 +- src/procs.cpp | 20 ++---- src/project.cpp | 3 +- 11 files changed, 99 insertions(+), 131 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9140cee..c908034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ PROJECT(dcc_original) -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.9) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +find_package(Qt5Core) OPTION(dcc_build_tests "Enable unit tests." OFF) #SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}) @@ -9,7 +12,7 @@ IF(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)") ADD_DEFINITIONS(/W4) ELSE() #-D_GLIBCXX_DEBUG - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall --std=c++0x") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall --std=c++11") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} " ) #--coverage ENDIF() @@ -34,6 +37,7 @@ INCLUDE_DIRECTORIES( ${LLVM_INCLUDE_DIRS} ) set(dcc_LIB_SOURCES + src/CallConvention.cpp src/ast.cpp src/backend.cpp src/bundle.cpp @@ -73,7 +77,6 @@ set(dcc_LIB_SOURCES src/symtab.cpp src/udm.cpp src/BasicBlock.cpp - src/CallConvention.cpp ) set(dcc_SOURCES src/dcc.cpp @@ -100,6 +103,7 @@ set(dcc_HEADERS include/idioms/shift_idioms.h include/idioms/xor_idioms.h include/locident.h + include/CallConvention.h include/perfhlib.h include/project.h include/scanner.h @@ -109,7 +113,6 @@ set(dcc_HEADERS include/Procedure.h include/StackFrame.h include/BasicBlock.h - include/CallConvention.h ) SOURCE_GROUP(Source FILES ${dcc_SOURCES}) @@ -120,7 +123,8 @@ ADD_LIBRARY(dcc_lib STATIC ${dcc_LIB_SOURCES} ${dcc_HEADERS}) ADD_EXECUTABLE(dcc_original ${dcc_SOURCES} ${dcc_HEADERS}) ADD_DEPENDENCIES(dcc_original dcc_lib) -TARGET_LINK_LIBRARIES(dcc_original LLVMSupport dcc_lib disasm_s ${REQ_LLVM_LIBRARIES} LLVMSupport) +TARGET_LINK_LIBRARIES(dcc_original dcc_lib disasm_s ${REQ_LLVM_LIBRARIES} ncurses LLVMSupport) +qt5_use_modules(dcc_original Core) if(dcc_build_tests) ADD_SUBDIRECTORY(src) endif() diff --git a/include/dcc.h b/include/dcc.h index 390b795..20a7474 100644 --- a/include/dcc.h +++ b/include/dcc.h @@ -26,7 +26,7 @@ extern bundle cCode; /* Output C procedure's declaration and code */ /**** Global variables ****/ -extern char *asm1_name, *asm2_name; /* Assembler output filenames */ +extern std::string asm1_name, asm2_name; /* Assembler output filenames */ typedef struct { /* Command line option flags */ unsigned verbose : 1; @@ -37,7 +37,7 @@ typedef struct { /* Command line option flags */ unsigned Stats : 1; unsigned Interact : 1; /* Interactive mode */ unsigned Calls : 1; /* Follow register indirect calls */ - char filename[80]; /* The input filename */ + std::string filename; /* The input filename */ } OPTION; extern OPTION option; /* Command line options */ @@ -86,7 +86,7 @@ public: void udm(void); /* udm.c */ void freeCFG(BB * cfg); /* graph.c */ BB * newBB(BB *, int, int, uint8_t, int, Function *); /* graph.c */ -void BackEnd(char *filename, CALL_GRAPH *); /* backend.c */ +void BackEnd(const std::string &filename, CALL_GRAPH *); /* backend.c */ extern char *cChar(uint8_t c); /* backend.c */ eErrorId scan(uint32_t ip, ICODE &p); /* scanner.c */ void parse (CALL_GRAPH * *); /* parser.c */ diff --git a/include/symtab.h b/include/symtab.h index ed697e3..f2410cd 100644 --- a/include/symtab.h +++ b/include/symtab.h @@ -36,21 +36,13 @@ struct SYM : public SymbolCommon struct STKSYM : public SymbolCommon { typedef int16_t tLabel; - Expr *actual; /* Expression tree of actual parameter */ - AstIdent *regs; /* For register arguments only */ - tLabel label; /* Immediate off from BP (+:args, -:params) */ - uint8_t regOff; /* Offset is a register (e.g. SI, DI) */ - bool hasMacro; /* This type needs a macro */ + Expr *actual=0; /* Expression tree of actual parameter */ + AstIdent *regs=0; /* For register arguments only */ + tLabel label=0; /* Immediate off from BP (+:args, -:params) */ + uint8_t regOff=0; /* Offset is a register (e.g. SI, DI) */ + bool hasMacro=false; /* This type needs a macro */ std::string macro; /* Macro name */ - bool invalid; /* Boolean: invalid entry in formal arg list*/ - STKSYM() - { - actual=0; - regs=0; - label=0; - regOff=0; - invalid=hasMacro = false; - } + bool invalid=false; /* Boolean: invalid entry in formal arg list*/ void setArgName(int i) { char buf[32]; diff --git a/regression_tester.rb b/regression_tester.rb index a860dbf..b96e78a 100755 --- a/regression_tester.rb +++ b/regression_tester.rb @@ -14,9 +14,9 @@ def perform_test(exepath,filepath,outname,args) filepath=path_local(filepath) joined_args = args.join(' ') printf("calling:" + "#{exepath} -a1 #{joined_args} -o#{output_path}.a1 #{filepath}\n") - STDERR << "Errors for : #{filepath}" - result = `#{exepath} -a1 -o#{output_path}.a1 #{filepath}` - result = `#{exepath} -a2 #{joined_args} -o#{output_path}.a2 #{filepath}` + STDERR << "Errors for : #{filepath}\n" + result = `#{exepath} -a 1 -o#{output_path}.a1 #{filepath}` + result = `#{exepath} -a 2 #{joined_args} -o#{output_path}.a2 #{filepath}` result = `#{exepath} #{joined_args} -o#{output_path} #{filepath}` puts result p $? diff --git a/src/backend.cpp b/src/backend.cpp index 03c5d52..874cb03 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -167,7 +167,7 @@ void Project::writeGlobSymTable() /* Writes the header information and global variables to the output C file * fp. */ -static void writeHeader (std::ostream &_ios, char *fileName) +static void writeHeader (std::ostream &_ios, const char *fileName) { PROG &prog(Project::get()->prog); /* Write header information */ @@ -341,7 +341,7 @@ static void backBackEnd (CALL_GRAPH * pcallGraph, std::ostream &_ios) /* Invokes the necessary routines to produce code one procedure at a time. */ -void BackEnd (char *fileName, CALL_GRAPH * pcallGraph) +void BackEnd (const std::string &fileName, CALL_GRAPH * pcallGraph) { std::ofstream fs; /* Output C file */ @@ -356,7 +356,7 @@ void BackEnd (char *fileName, CALL_GRAPH * pcallGraph) printf ("dcc: Writing C beta file %s\n", outNam.c_str()); /* Header information */ - writeHeader (fs, option.filename); + writeHeader (fs, option.filename.c_str()); /* Initialize total Icode instructions statistics */ stats.totalLL = 0; diff --git a/src/chklib.cpp b/src/chklib.cpp index ca45627..ae78bfa 100644 --- a/src/chklib.cpp +++ b/src/chklib.cpp @@ -68,7 +68,6 @@ void readFileSection(uint16_t* p, int len, FILE *_file); void cleanup(void); void checkStartup(STATE *state); void readProtoFile(void); -void fixNewline(char *s); int searchPList(char *name); void checkHeap(char *msg); /* For debugging */ diff --git a/src/dcc.cpp b/src/dcc.cpp index 08fae64..d1e0654 100644 --- a/src/dcc.cpp +++ b/src/dcc.cpp @@ -4,13 +4,15 @@ * (C) Cristina Cifuentes ****************************************************************************/ +#include +#include #include #include "dcc.h" #include "project.h" #include "CallGraph.h" /* Global variables - extern to other modules */ -extern char *asm1_name, *asm2_name; /* Assembler output filenames */ +extern std::string asm1_name, asm2_name; /* Assembler output filenames */ extern SYMTAB symtab; /* Global symbol table */ extern STATS stats; /* cfg statistics */ //PROG prog; /* programs fields */ @@ -40,6 +42,7 @@ static void displayTotalStats(void); /**************************************************************************** * main ***************************************************************************/ +#include #include using namespace llvm; bool TVisitor(raw_ostream &OS, RecordKeeper &Records) @@ -111,11 +114,68 @@ int testTblGen(int argc, char **argv) exit(0); +} +void setupOptions(QCoreApplication &app) { + //[-a1a2cmsi] + QCommandLineParser parser; + parser.setApplicationDescription("dcc"); + parser.addHelpOption(); + //parser.addVersionOption(); + //QCommandLineOption showProgressOption("p", QCoreApplication::translate("main", "Show progress during copy")); + QCommandLineOption boolOpts[] { + QCommandLineOption {"v", QCoreApplication::translate("main", "verbose")}, + QCommandLineOption {"V", QCoreApplication::translate("main", "very verbose")}, + QCommandLineOption {"c", QCoreApplication::translate("main", "Follow register indirect calls")}, + QCommandLineOption {"m", QCoreApplication::translate("main", "Print memory maps of program")}, + QCommandLineOption {"s", QCoreApplication::translate("main", "Print stats")} + }; + for(QCommandLineOption &o : boolOpts) { + parser.addOption(o); + } + QCommandLineOption assembly("a", QCoreApplication::translate("main", "Produce assembly"),"assembly_level"); + // A boolean option with multiple names (-f, --force) + //QCommandLineOption forceOption(QStringList() << "f" << "force", "Overwrite existing files."); + // An option with a value + QCommandLineOption targetFileOption(QStringList() << "o" << "output", + QCoreApplication::translate("main", "Place output into ."), + QCoreApplication::translate("main", "file")); + parser.addOption(targetFileOption); + parser.addOption(assembly); + //parser.addOption(forceOption); + // Process the actual command line arguments given by the user + parser.addPositionalArgument("source", QCoreApplication::translate("main", "Dos Executable file to decompile.")); + parser.process(app); + + const QStringList args = parser.positionalArguments(); + if(args.empty()) { + parser.showHelp(); + } + // source is args.at(0), destination is args.at(1) + option.verbose = parser.isSet(boolOpts[0]); + option.VeryVerbose = parser.isSet(boolOpts[1]); + if(parser.isSet(assembly)) { + option.asm1 = parser.value(assembly).toInt()==1; + option.asm2 = parser.value(assembly).toInt()==2; + } + option.Map = parser.isSet(boolOpts[3]); + option.Stats = parser.isSet(boolOpts[4]); + option.Interact = false; + option.Calls = parser.isSet(boolOpts[2]); + option.filename = args.first().toStdString(); + if(parser.isSet(targetFileOption)) + asm1_name = asm2_name = parser.value(targetFileOption).toStdString(); + else if(option.asm1 || option.asm2) { + asm1_name = option.filename+".a1"; + asm2_name = option.filename+".a2"; + } + } int main(int argc, char **argv) { - /* Extract switches and filename */ - strcpy(option.filename, initargs(argc, argv)); + QCoreApplication app(argc,argv); + + QCoreApplication::setApplicationVersion("0.1"); + setupOptions(app); /* Front end reads in EXE or COM file, parses it into I-code while * building the call graph and attaching appropriate bits of code for @@ -138,98 +198,16 @@ int main(int argc, char **argv) * analysis, data flow etc. and outputs it to output file ready for * re-compilation. */ - BackEnd(asm1_name ? asm1_name:option.filename, Project::get()->callGraph); + BackEnd(!asm1_name.empty() ? asm1_name:option.filename, Project::get()->callGraph); Project::get()->callGraph->write(); if (option.Stats) displayTotalStats(); - /* - freeDataStructures(pProcList); -*/ return 0; } -/**************************************************************************** - * initargs - Extract command line arguments - ***************************************************************************/ -static char *initargs(int argc, char *argv[]) -{ - char *pc; - - while (--argc > 0 && (*++argv)[0] == '-') - { - for (pc = argv[0]+1; *pc; pc++) - switch (*pc) - { - case 'a': /* Print assembler listing */ - if (*(pc+1) == '2') - option.asm2 = true; - else - option.asm1 = true; - if (*(pc+1) == '1' || *(pc+1) == '2') - pc++; - break; - case 'c': - option.Calls = true; - break; - case 'i': - option.Interact = true; - break; - case 'm': /* Print memory map */ - option.Map = true; - break; - case 's': /* Print Stats */ - option.Stats = true; - break; - case 'V': /* Very verbose => verbose */ - option.VeryVerbose = true; - case 'v': - option.verbose = true; /* Make everything verbose */ - break; - case 'o': /* assembler output file */ - if (*(pc+1)) { - asm1_name = asm2_name = pc+1; - goto NextArg; - } - else if (--argc > 0) { - asm1_name = asm2_name = *++argv; - goto NextArg; - } - default: - fatalError(INVALID_ARG, *pc); - return *argv; - } -NextArg:; - } - - if (argc == 1) - { - if (option.asm1 || option.asm2) - { - if (! asm1_name) - { - asm1_name = strcpy((char*)malloc(strlen(*argv)+4), *argv); - pc = strrchr(asm1_name, '.'); - if (pc > strrchr(asm1_name, '/')) - { - *pc = '\0'; - } - asm2_name = (char*)malloc(strlen(asm1_name)+4) ; - strcat(strcpy(asm2_name, asm1_name), ".a2"); - unlink(asm2_name); - strcat(asm1_name, ".a1"); - } - unlink(asm1_name); /* Remove asm output files */ - } - return *argv; /* filename of the program to decompile */ - } - - fatalError(USAGE); - return *argv; // does not reach this. -} - static void displayTotalStats () /* Displays final statistics for the complete program */ diff --git a/src/disassem.cpp b/src/disassem.cpp index 0baba18..6ea0656 100644 --- a/src/disassem.cpp +++ b/src/disassem.cpp @@ -153,7 +153,7 @@ void Disassembler::disassem(Function * ppProc) m_fp.open(p,ios_base::app); if (!m_fp.is_open()) { - fatalError(CANNOT_OPEN, p); + fatalError(CANNOT_OPEN, p.c_str()); } } /* Create temporary code array */ diff --git a/src/frontend.cpp b/src/frontend.cpp index 677ff68..1f0e102 100644 --- a/src/frontend.cpp +++ b/src/frontend.cpp @@ -82,7 +82,7 @@ bool DccFrontend::FrontEnd () if (option.asm1) { - printf("dcc: writing assembler file %s\n", asm1_name); + printf("dcc: writing assembler file %s\n", asm1_name.c_str()); } /* Search through code looking for impure references and flag them */ diff --git a/src/procs.cpp b/src/procs.cpp index e083573..0f618bf 100644 --- a/src/procs.cpp +++ b/src/procs.cpp @@ -27,7 +27,6 @@ const char *indentStr(int indLevel) // Indentation according to the depth of the * not exist. */ void CALL_GRAPH::insertArc (ilFunction newProc) { - CALL_GRAPH *pcg; /* Check if procedure already exists */ @@ -35,7 +34,7 @@ void CALL_GRAPH::insertArc (ilFunction newProc) if(res!=outEdges.end()) return; /* Include new arc */ - pcg = new CALL_GRAPH; + CALL_GRAPH *pcg = new CALL_GRAPH; pcg->proc = newProc; outEdges.push_back(pcg); } @@ -49,13 +48,10 @@ bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee) insertArc (callee); return true; } - else - { for (CALL_GRAPH *edg : outEdges) if (edg->insertCallGraph (caller, callee)) return true; - return (false); - } + return false; } bool CALL_GRAPH::insertCallGraph(Function *caller, ilFunction callee) @@ -333,7 +329,6 @@ void STKFRAME::adjustForArgType(size_t numArg_, hlType actType_) { hlType forType; STKSYM * psym, * nsym; - int off; /* If formal argument does not exist, do not create new ones, just * ignore actual argument */ @@ -341,7 +336,7 @@ void STKFRAME::adjustForArgType(size_t numArg_, hlType actType_) return; /* Find stack offset for this argument */ - off = m_minOff; + int off = m_minOff; size_t i=0; for(STKSYM &s : *this) // walk formal arguments upto numArg_ { @@ -353,7 +348,6 @@ void STKFRAME::adjustForArgType(size_t numArg_, hlType actType_) /* Find formal argument */ //psym = &at(numArg_); - //i = numArg_; //auto iter=std::find_if(sym.begin(),sym.end(),[off](STKSYM &s)->bool {s.off==off;}); auto iter=std::find_if(begin()+numArg_,end(),[off](STKSYM &s)->bool {return s.label==off;}); if(iter==end()) // symbol not found @@ -361,15 +355,16 @@ void STKFRAME::adjustForArgType(size_t numArg_, hlType actType_) psym = &(*iter); forType = psym->type; - if (forType != actType_) - { + if (forType == actType_) + return; switch (actType_) { case TYPE_UNKNOWN: case TYPE_BYTE_SIGN: case TYPE_BYTE_UNSIGN: case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN: case TYPE_RECORD: break; - case TYPE_LONG_UNSIGN: case TYPE_LONG_SIGN: + case TYPE_LONG_UNSIGN: + case TYPE_LONG_SIGN: if ((forType == TYPE_WORD_UNSIGN) || (forType == TYPE_WORD_SIGN) || (forType == TYPE_UNKNOWN)) @@ -395,6 +390,5 @@ void STKFRAME::adjustForArgType(size_t numArg_, hlType actType_) default: fprintf(stderr,"STKFRAME::adjustForArgType unhandled actType_ %d \n",actType_); } /* eos */ - } } diff --git a/src/project.cpp b/src/project.cpp index 0140292..23d298e 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1,10 +1,11 @@ #include #include "dcc.h" +#include "CallGraph.h" #include "project.h" #include "Procedure.h" using namespace std; //Project g_proj; -char *asm1_name, *asm2_name; /* Assembler output filenames */ +string asm1_name, asm2_name; /* Assembler output filenames */ SYMTAB symtab; /* Global symbol table */ STATS stats; /* cfg statistics */ //PROG prog; /* programs fields */