dcc/src/dcc.cpp

164 lines
5.9 KiB
C++

/*****************************************************************************
* dcc decompiler
* Reads the command line switches and then executes each major section in turn
* (C) Cristina Cifuentes
****************************************************************************/
#include "dcc.h"
#include "msvc_fixes.h"
#include "project.h"
#include "CallGraph.h"
#include "DccFrontend.h"
#include <cstring>
#include <iostream>
#include <QtCore/QCoreApplication>
#include <QtWidgets/QApplication>
#include <QCommandLineParser>
#include <QtCore/QFile>
#include "ui/DccMainWindow.h"
/* Global variables - extern to other modules */
extern QString asm1_name, asm2_name; /* Assembler output filenames */
extern SYMTAB symtab; /* Global symbol table */
extern STATS stats; /* cfg statistics */
extern OPTION option; /* Command line options */
static char *initargs(int argc, char *argv[]);
static void displayTotalStats(void);
/****************************************************************************
* main
***************************************************************************/
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");
QCommandLineOption targetFileOption(QStringList() << "o" << "output",
QCoreApplication::translate("main", "Place output into <file>."),
QCoreApplication::translate("main", "file"));
QCommandLineOption entryPointOption(QStringList() << "E",
QCoreApplication::translate("main", "Custom entry point as hex"),
QCoreApplication::translate("main", "offset"),
"0"
);
parser.addOption(targetFileOption);
parser.addOption(assembly);
parser.addOption(entryPointOption);
//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();
option.CustomEntryPoint = parser.value(entryPointOption).toUInt(0,16);
if(parser.isSet(targetFileOption))
asm1_name = asm2_name = parser.value(targetFileOption);
else if(option.asm1 or option.asm2) {
asm1_name = option.filename+".a1";
asm2_name = option.filename+".a2";
}
}
int main(int argc, char **argv)
{
QCoreApplication::setApplicationName("dcc");
QCoreApplication::setApplicationVersion("0.2");
if(argc==1) {
QApplication app(argc,argv);
DccMainWindow win;
win.show();
return app.exec();
}
QCoreApplication app(argc,argv);
setupOptions(app);
Project *proj = Project::get();
/* 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
* each procedure.
*/
proj->create(option.filename);
DccFrontend fe(&app);
proj->addLoadCommands(option.filename);
proj->processAllCommands();
if(proj->m_error_state) {
proj->dumpAllErrors();
return -1;
}
if (option.verbose)
proj->prog.displayLoadInfo();
if(false==fe.FrontEnd ())
return -1;
if(option.asm1)
return 0;
/* In the middle is a so called Universal Decompiling Machine.
* It processes the procedure list and I-code and attaches where it can
* to each procedure an optimised cfg and ud lists
*/
udm();
if(option.asm2)
return 0;
/* Back end converts each procedure into C using I-code, interval
* analysis, data flow etc. and outputs it to output file ready for
* re-compilation.
*/
BackEnd(proj->callGraph);
proj->callGraph->write();
if (option.Stats)
displayTotalStats();
return 0;
}
static void
displayTotalStats ()
/* Displays final statistics for the complete program */
{
printf ("\nFinal Program Statistics\n");
printf (" Total number of low-level Icodes : %d\n", stats.totalLL);
printf (" Total number of high-level Icodes: %d\n", stats.totalHL);
printf (" Total reduction of instructions : %2.2f%%\n", 100.0 -
(stats.totalHL * 100.0) / stats.totalLL);
}