1 /*-
2  * Copyright (c) 2006, 2007 CTPP Team
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 4. Neither the name of the CTPP Team nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *      VMEmulator.cpp
29  *
30  * $CTPP$
31  */
32 
33 #include <CTPP2JSONParser.hpp>
34 #include <CTPP2FileOutputCollector.hpp>
35 #include <CTPP2FileLogger.hpp>
36 #include <CTPP2SyscallFactory.hpp>
37 #include <CTPP2VMDebugInfo.hpp>
38 #include <CTPP2VM.hpp>
39 #include <CTPP2VMFileLoader.hpp>
40 #include <CTPP2VMSTDLib.hpp>
41 #include <CTPP2VMStackException.hpp>
42 #include <CTPP2GetText.hpp>
43 
44 #include <sys/stat.h>
45 
46 #ifdef HAVE_SYS_TIME_H
47     #include <sys/time.h>
48 #endif
49 
50 #ifdef WIN32
51     #include <CTPP2Time.h>
52 #endif
53 
54 #include <stdio.h>
55 #include <string.h>
56 
57 #include <memory>
58 
59 using namespace CTPP;
60 
main(int argc,char ** argv)61 int main(int argc, char ** argv)
62 {
63 	INT_32 iRetCode = EX_SOFTWARE;
64 
65 	if (argc != 2 && argc != 3 && argc != 4 && argc != 5)
66 	{
67 		fprintf(stdout, "CTPP2 virtual machine v" CTPP_VERSION " (" CTPP_IDENT "). Copyright (c) 2004-2011 CTPP Dev. Team.\n\n");
68 		fprintf(stderr, "usage: %s file.name [data.json] [output.txt | 0] [translation.mo | 0] [limit of steps]\n", argv[0]);
69 		return EX_USAGE;
70 	}
71 
72 	// Initialize Standard CTPP library
73 	SyscallFactory oSyscallFactory(100);
74 	// Load standard library
75 	STDLibInitializer::InitLibrary(oSyscallFactory);
76 	// Output
77 	std::auto_ptr<FileOutputCollector> pOutputCollector(new FileOutputCollector(stdout));
78 
79 	if (argc >= 4 && strncmp(argv[3], "0", sizeof(argv[3])) != 0) { pOutputCollector.reset(new FileOutputCollector(argv[3], "w+")); }
80 
81 
82 	CTPP2GetText oGetText;
83 	if (argc >= 5 && strncmp(argv[4], "0", sizeof(argv[4])) != 0) { oGetText.AddTranslation(argv[4], "test", "unknown"); }
84 	oGetText.InitSTDLibFunction(oSyscallFactory);
85 	oGetText.SetLanguage(oSyscallFactory, "unknown");
86 	oGetText.SetDefaultDomain("test");
87 
88 	UINT_32 iStepsLimit = 10240;
89 	if(argc == 6) { iStepsLimit = atoi(argv[5]); }
90 	else
91 	{
92 		fprintf(stderr, "WARNING: [limit of steps] not set, use default value of %d\n", iStepsLimit);
93 	}
94 
95 	try
96 	{
97 		// Load program from file
98 		VMFileLoader oLoader(argv[1]);
99 
100 		// Get program core
101 		const VMMemoryCore * pVMMemoryCore = oLoader.GetCore();
102 
103 		CDT oHash(CDT::HASH_VAL);
104 
105 		// Load JSON data
106 		if(argc >= 3)
107 		{
108 			struct stat oStat;
109 			// Get file size
110 			if (stat(argv[2], &oStat) == -1 || oStat.st_size == 0) { fprintf(stderr, "ERROR: Cannot get size of file `%s`\n", argv[2]); return EX_SOFTWARE; }
111 
112 			// Allocate memory
113 			CHAR_8 * szJSONBuffer = (CHAR_8 *)malloc(oStat.st_size + 1);
114 			// Read from file
115 			FILE * F = fopen(argv[2], "rb");
116 			if (F == NULL) { fprintf(stderr, "ERROR: Cannot open file `%s` for reading\n", argv[2]); return EX_SOFTWARE; }
117 
118 			if (fread(szJSONBuffer, oStat.st_size, 1, F) != 1)
119 			{
120 				fprintf(stderr, "ERROR: Cannot read from file `%s`\n", argv[2]);
121 				fclose(F);
122 				free(szJSONBuffer);
123 				return EX_SOFTWARE;
124 			}
125 
126 			szJSONBuffer[oStat.st_size] = '\0';
127 
128 			CTPP2JSONParser oJSONParser(oHash);
129 			CCHAR_P szEnd = szJSONBuffer + oStat.st_size;
130 			oJSONParser.Parse(szJSONBuffer, szEnd);
131 
132 			// All Done
133 			fclose(F);
134 			// All done with loading
135 			free(szJSONBuffer);
136 		}
137 		else
138 		{
139 			fprintf(stderr, "WARNING: [data.json] not given\n");
140 		}
141 
142 		// Logger
143 		FileLogger oLogger(stderr);
144 
145 		// Run program
146 		VM oVM(&oSyscallFactory, 10240, 10240, iStepsLimit);
147 
148 		struct timeval sTimeValLocBegin;
149 		gettimeofday(&sTimeValLocBegin, NULL);
150 
151 		UINT_32 iIP = 0;
152 		oVM.Init(pVMMemoryCore, pOutputCollector.get(), &oLogger);
153 		oVM.Run(pVMMemoryCore, pOutputCollector.get(), iIP, oHash, &oLogger);
154 
155 		struct timeval sTimeValLocEnd;
156 		gettimeofday(&sTimeValLocEnd, NULL);
157 
158 		fprintf(stderr, "Completed in %f seconds.\n", (1.0 * (sTimeValLocEnd.tv_sec - sTimeValLocBegin.tv_sec) + 1.0 * (sTimeValLocEnd.tv_usec - sTimeValLocBegin.tv_usec) / 1000000));
159 
160 		iRetCode = EX_OK;
161 	}
162 	// CDT
163 	catch(CDTTypeCastException  & e) { fprintf(stderr, "ERROR: Type Cast %s\n", e.what());                                    }
164 	catch(CDTAccessException    & e) { fprintf(stderr, "ERROR: Array index out of bounds: %s\n", e.what());                   }
165 
166 	// Virtual machine
167 	catch(IllegalOpcode         & e) { fprintf(stderr, "ERROR: Illegal opcode 0x%08X at 0x%08X\n", e.GetOpcode(), e.GetIP()); }
168 	catch(InvalidSyscall        & e)
169 	{
170 		if (e.GetIP() != 0)
171 		{
172 			VMDebugInfo oVMDebugInfo(e.GetDebugInfo());
173 			fprintf(stderr, "ERROR: %s at 0x%08X (Template file \"%s\", Line %d, Pos %d)\n", e.what(), e.GetIP(), e.GetSourceName(), oVMDebugInfo.GetLine(), oVMDebugInfo.GetLinePos());
174 		}
175 		else
176 		{
177 			fprintf(stderr, "Unsupported syscall: \"%s\"\n", e.what());
178 		}
179 	}
180 	catch(InvalidCall           & e)
181 	{
182 		VMDebugInfo oVMDebugInfo(e.GetDebugInfo());
183 		fprintf(stderr, "ERROR: at 0x%08X: Invalid block name \"%s\" in file \"%s\", Line %d, Pos %d\n",  e.GetIP(), e.what(), e.GetSourceName(), oVMDebugInfo.GetLine(), oVMDebugInfo.GetLinePos());
184 	}
185 	catch(CodeSegmentOverrun    & e) { fprintf(stderr, "ERROR: %s at 0x%08X\n", e.what(),  e.GetIP());                        }
186 	catch(StackOverflow         & e) { fprintf(stderr, "ERROR: Stack overflow at 0x%08X\n", e.GetIP());                       }
187 	catch(StackUnderflow        & e) { fprintf(stderr, "ERROR: Stack underflow at 0x%08X\n", e.GetIP());                      }
188 	catch(ExecutionLimitReached & e) { fprintf(stderr, "ERROR: Execution limit of %d step(s) reached at 0x%08X\n", iStepsLimit, e.GetIP()); }
189 	catch(VMException           & e) { fprintf(stderr, "ERROR: VM generic exception: %s at 0x%08X\n", e.what(), e.GetIP()); }
190 
191 	// CTPP
192 	catch(CTPPLogicError        & e) { fprintf(stderr, "ERROR: %s\n", e.what());                                              }
193 	catch(CTPPUnixException     & e) { fprintf(stderr, "ERROR: I/O in %s: %s\n", e.what(), strerror(e.ErrNo()));              }
194 	catch(CTPPException         & e) { fprintf(stderr, "ERROR: CTPP Generic exception: %s\n", e.what());                      }
195 
196 	// Destroy standard library
197 	STDLibInitializer::DestroyLibrary(oSyscallFactory);
198 
199 	// make valgrind happy
200 	fclose(stdin);
201 	fclose(stdout);
202 	fclose(stderr);
203 
204 return iRetCode;
205 }
206 // End.
207 
208