1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/config-manager.h"
24 #include "common/debug.h"
25 #include "common/debug-channels.h"
26 
27 #include "sci/sci.h"
28 #include "sci/console.h"
29 #include "sci/engine/features.h"
30 #include "sci/engine/guest_additions.h"
31 #include "sci/engine/state.h"
32 #include "sci/engine/kernel.h"
33 #include "sci/engine/object.h"
34 #include "sci/engine/script.h"
35 #include "sci/engine/seg_manager.h"
36 #include "sci/engine/selector.h"	// for SELECTOR
37 #include "sci/engine/gc.h"
38 #include "sci/engine/workarounds.h"
39 #include "sci/engine/scriptdebug.h"
40 
41 namespace Sci {
42 
43 const reg_t NULL_REG = {0, 0};
44 const reg_t SIGNAL_REG = {0, SIGNAL_OFFSET};
45 const reg_t TRUE_REG = {0, 1};
46 // Enable the define below to have the VM abort on cases where a conditional
47 // statement is followed by an unconditional jump (which will most likely lead
48 // to an infinite loop). Aids in detecting script bugs such as #3040722.
49 //#define ABORT_ON_INFINITE_LOOP
50 
51 // validation functionality
52 
validate_property(EngineState * s,Object * obj,int index)53 static reg_t &validate_property(EngineState *s, Object *obj, int index) {
54 	// A static dummy reg_t, which we return if obj or index turn out to be
55 	// invalid. Note that we cannot just return NULL_REG, because client code
56 	// may modify the value of the returned reg_t.
57 	static reg_t dummyReg = NULL_REG;
58 
59 	// If this occurs, it means there's probably something wrong with the garbage
60 	// collector, so don't hide it with fake return values
61 	if (!obj)
62 		error("validate_property: Sending to disposed object");
63 
64 	if (getSciVersion() == SCI_VERSION_3)
65 		index = obj->locateVarSelector(s->_segMan, index);
66 	else
67 		index >>= 1;
68 
69 	if (index < 0 || (uint)index >= obj->getVarCount()) {
70 		// This is same way sierra does it and there are some games, that contain such scripts like
71 		//  iceman script 998 (fred::canBeHere, executed right at the start)
72 		debugC(kDebugLevelVM, "[VM] Invalid property #%d (out of [0..%d]) requested from object %04x:%04x (%s)",
73 			index, obj->getVarCount(), PRINT_REG(obj->getPos()), s->_segMan->getObjectName(obj->getPos()));
74 		return dummyReg;
75 	}
76 
77 	return obj->getVariableRef(index);
78 }
79 
validate_stack_addr(EngineState * s,StackPtr sp)80 static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) {
81 	if (sp >= s->stack_base && sp < s->stack_top)
82 		return sp;
83 	else
84 	error("[VM] Stack index %d out of valid range [%d..%d]",
85 		(int)(sp - s->stack_base), 0, (int)(s->stack_top - s->stack_base - 1));
86 }
87 
validate_variable(reg_t * r,reg_t * stack_base,int type,int max,int index)88 static bool validate_variable(reg_t *r, reg_t *stack_base, int type, int max, int index) {
89 	const char *names[4] = {"global", "local", "temp", "param"};
90 
91 	if (index < 0 || index >= max) {
92 		Common::String txt = Common::String::format(
93 							"[VM] Attempt to use invalid %s variable %04x ",
94 							names[type], index);
95 		if (max == 0)
96 			txt += "(variable type invalid)";
97 		else
98 			txt += Common::String::format("(out of range [%d..%d])", 0, max - 1);
99 
100 		if (type == VAR_PARAM || type == VAR_TEMP) {
101 			int total_offset = r - stack_base;
102 			if (total_offset < 0 || total_offset >= VM_STACK_SIZE) {
103 				// Fatal, as the game is trying to do an OOB access
104 				error("%s. [VM] Access would be outside even of the stack (%d); access denied", txt.c_str(), total_offset);
105 				return false;
106 			} else {
107 				debugC(kDebugLevelVM, "%s", txt.c_str());
108 				debugC(kDebugLevelVM, "[VM] Access within stack boundaries; access granted.");
109 				return true;
110 			}
111 		}
112 		return false;
113 	}
114 
115 	return true;
116 }
117 
read_var(EngineState * s,int type,int index)118 static reg_t read_var(EngineState *s, int type, int index) {
119 	if (validate_variable(s->variables[type], s->stack_base, type, s->variablesMax[type], index)) {
120 		if (s->variables[type][index].getSegment() == kUninitializedSegment) {
121 			switch (type) {
122 			case VAR_TEMP: {
123 				// Uninitialized read on a temp
124 				//  We need to find correct replacements for each situation manually
125 				SciCallOrigin originReply;
126 				SciWorkaroundSolution solution = trackOriginAndFindWorkaround(index, uninitializedReadWorkarounds, &originReply);
127 				if (solution.type == WORKAROUND_NONE) {
128 #ifdef RELEASE_BUILD
129 					// If we are running an official ScummVM release -> fake 0 in unknown cases
130 					warning("Uninitialized read for temp %d from %s", index, originReply.toString().c_str());
131 
132 					s->variables[type][index] = NULL_REG;
133 					break;
134 #else
135 					error("Uninitialized read for temp %d from %s", index, originReply.toString().c_str());
136 #endif
137 				}
138 				assert(solution.type == WORKAROUND_FAKE);
139 				s->variables[type][index] = make_reg(0, solution.value);
140 				break;
141 			}
142 			case VAR_PARAM: {
143 				// Out-of-bounds read for a parameter that goes onto stack and hits an uninitialized temp
144 				//  We need to find correct replacements for each situation manually
145 				SciCallOrigin originReply;
146 				SciWorkaroundSolution solution = trackOriginAndFindWorkaround(index, uninitializedReadForParamWorkarounds, &originReply);
147 				if (solution.type == WORKAROUND_NONE) {
148 					warning("Uninitialized read for parameter %d from %s", index, originReply.toString().c_str());
149 					return NULL_REG;
150 				} else {
151 					return make_reg(0, solution.value);
152 				}
153 			}
154 			default:
155 				break;
156 			}
157 		}
158 		return s->variables[type][index];
159 	} else
160 		return s->r_acc;
161 }
162 
write_var(EngineState * s,int type,int index,reg_t value)163 static void write_var(EngineState *s, int type, int index, reg_t value) {
164 	if (validate_variable(s->variables[type], s->stack_base, type, s->variablesMax[type], index)) {
165 
166 		// WORKAROUND: This code is needed to work around a probable script bug, or a
167 		// limitation of the original SCI engine, which can be observed in LSL5.
168 		//
169 		// In some games, ego walks via the "Grooper" object, in particular its "stopGroop"
170 		// child. In LSL5, during the game, ego is swapped from Larry to Patti. When this
171 		// happens in the original interpreter, the new actor is loaded in the same memory
172 		// location as the old one, therefore the client variable in the stopGroop object
173 		// points to the new actor. This is probably why the reference of the stopGroop
174 		// object is never updated (which is why I mentioned that this is either a script
175 		// bug or some kind of limitation).
176 		//
177 		// In our implementation, each new object is loaded in a different memory location,
178 		// and we can't overwrite the old one. This means that in our implementation,
179 		// whenever ego is changed, we need to update the "client" variable of the
180 		// stopGroop object, which points to ego, to the new ego object. If this is not
181 		// done, ego's movement will not be updated properly, so the result is
182 		// unpredictable (for example in LSL5, Patti spins around instead of walking).
183 		if (index == kGlobalVarEgo && type == VAR_GLOBAL && getSciVersion() > SCI_VERSION_0_EARLY) {
184 			reg_t stopGroopPos = s->_segMan->findObjectByName("stopGroop");
185 			if (!stopGroopPos.isNull()) {	// does the game have a stopGroop object?
186 				// Find the "client" member variable of the stopGroop object, and update it
187 				ObjVarRef varp;
188 				if (lookupSelector(s->_segMan, stopGroopPos, SELECTOR(client), &varp, NULL) == kSelectorVariable) {
189 					reg_t *clientVar = varp.getPointer(s->_segMan);
190 					*clientVar = value;
191 				}
192 			}
193 		}
194 
195 		// If we are writing an uninitialized value into a temp, we remove the uninitialized segment
196 		//  this happens at least in sq1/room 44 (slot-machine), because a send is missing parameters, then
197 		//  those parameters are taken from uninitialized stack and afterwards they are copied back into temps
198 		//  if we don't remove the segment, we would get false-positive uninitialized reads later
199 		if (type == VAR_TEMP && value.getSegment() == kUninitializedSegment)
200 			value.setSegment(0);
201 
202 		s->variables[type][index] = value;
203 
204 		g_sci->_guestAdditions->writeVarHook(type, index, value);
205 	}
206 }
207 
208 // Operating on the stack
209 // 16 bit:
210 #define PUSH(v) PUSH32(make_reg(0, v))
211 // 32 bit:
212 #define PUSH32(a) (*(validate_stack_addr(s, (s->xs->sp)++)) = (a))
213 #define POP32() (*(validate_stack_addr(s, --(s->xs->sp))))
214 
execute_method(EngineState * s,uint16 script,uint16 pubfunct,StackPtr sp,reg_t calling_obj,uint16 argc,StackPtr argp)215 ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackPtr sp, reg_t calling_obj, uint16 argc, StackPtr argp) {
216 	int seg = s->_segMan->getScriptSegment(script);
217 	Script *scr = s->_segMan->getScriptIfLoaded(seg);
218 
219 	if (!scr || scr->isMarkedAsDeleted()) { // Script not present yet?
220 		seg = s->_segMan->instantiateScript(script);
221 		scr = s->_segMan->getScript(seg);
222 	}
223 
224 	// Check if a breakpoint is set on this method
225 	g_sci->checkExportBreakpoint(script, pubfunct);
226 
227 	uint32 exportAddr = scr->validateExportFunc(pubfunct, false);
228 	if (!exportAddr)
229 		return NULL;
230 
231 	assert(argp[0].toUint16() == argc); // The first argument is argc
232 	ExecStack xstack(calling_obj, calling_obj, sp, argc, argp,
233 						seg, make_reg32(seg, exportAddr), -1, -1, -1, pubfunct, -1,
234 						s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL);
235 	s->_executionStack.push_back(xstack);
236 	return &(s->_executionStack.back());
237 }
238 
_exec_varselectors(EngineState * s)239 static void _exec_varselectors(EngineState *s) {
240 	// Executes all varselector read/write ops on the TOS
241 	while (!s->_executionStack.empty() && s->_executionStack.back().type == EXEC_STACK_TYPE_VARSELECTOR) {
242 		ExecStack &xs = s->_executionStack.back();
243 		reg_t *var = xs.getVarPointer(s->_segMan);
244 		if (!var) {
245 			error("Invalid varselector exec stack entry");
246 		} else {
247 			// varselector access?
248 			if (xs.argc) { // write?
249 				*var = xs.variables_argp[1];
250 
251 #ifdef ENABLE_SCI32
252 				updateInfoFlagViewVisible(s->_segMan->getObject(xs.addr.varp.obj), xs.addr.varp.varindex);
253 #endif
254 
255 			} else // No, read
256 				s->r_acc = *var;
257 		}
258 		s->_executionStack.pop_back();
259 	}
260 }
261 
262 
send_selector(EngineState * s,reg_t send_obj,reg_t work_obj,StackPtr sp,int framesize,StackPtr argp)263 ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPtr sp, int framesize, StackPtr argp) {
264 	// send_obj and work_obj are equal for anything but 'super'
265 	// Returns a pointer to the TOS exec_stack element
266 	assert(s);
267 
268 	reg_t funcp;
269 	Selector selector;
270 	int argc;
271 	int origin = s->_executionStack.size() - 1; // Origin: Used for debugging
272 	int activeBreakpointTypes = g_sci->_debugState._activeBreakpointTypes;
273 	ObjVarRef varp;
274 
275 	Common::List<ExecStack>::iterator prevElementIterator = s->_executionStack.end();
276 
277 	while (framesize > 0) {
278 		selector = argp->requireUint16();
279 		argp++;
280 		argc = argp->requireUint16();
281 
282 		if (argc > 0x800)	// More arguments than the stack could possibly accomodate for
283 			error("send_selector(): More than 0x800 arguments to function call");
284 
285 #ifdef ENABLE_SCI32
286 		g_sci->_guestAdditions->sendSelectorHook(send_obj, selector, argp);
287 #endif
288 
289 		SelectorType selectorType = lookupSelector(s->_segMan, send_obj, selector, &varp, &funcp);
290 		if (selectorType == kSelectorNone)
291 			error("Send to invalid selector 0x%x (%s) of object at %04x:%04x", 0xffff & selector, g_sci->getKernel()->getSelectorName(0xffff & selector).c_str(), PRINT_REG(send_obj));
292 
293 		ExecStackType stackType = EXEC_STACK_TYPE_VARSELECTOR;
294 		StackPtr curSP = NULL;
295 		reg_t curFP = make_reg32(0, 0);
296 		if (selectorType == kSelectorMethod) {
297 			stackType = EXEC_STACK_TYPE_CALL;
298 			curSP = sp;
299 			curFP = make_reg32(funcp.getSegment(), funcp.getOffset());
300 			sp = CALL_SP_CARRY; // Destroy sp, as it will be carried over
301 		}
302 
303 		if ((activeBreakpointTypes & (BREAK_SELECTOREXEC | BREAK_SELECTORREAD | BREAK_SELECTORWRITE))
304 		     || DebugMan.isDebugChannelEnabled(kDebugLevelScripts))
305 			debugSelectorCall(send_obj, selector, argc, argp, varp, funcp, s->_segMan, selectorType);
306 
307 		assert(argp[0].toUint16() == argc); // The first argument is argc
308 		ExecStack xstack(work_obj, send_obj, curSP, argc, argp,
309 							kUninitializedSegment, curFP, selector, -1, -1, -1, -1,
310 							origin, stackType);
311 
312 		if (selectorType == kSelectorVariable)
313 			xstack.addr.varp = varp;
314 
315 		// The new stack entries should be put on the stack in reverse order
316 		// so that the first one is executed first
317 		s->_executionStack.insert(prevElementIterator, xstack);
318 		// Decrement the stack end pointer so that it points to our recently
319 		// added element, so that the next insert() places it before this one.
320 		--prevElementIterator;
321 
322 		framesize -= (2 + argc);
323 		argp += argc + 1;
324 	}	// while (framesize > 0)
325 
326 	// Perform all varselector actions at the top of the stack immediately.
327 	// Note that there may be some behind method selector calls as well;
328 	// those will get executed by op_ret later.
329 	_exec_varselectors(s);
330 
331 	return s->_executionStack.empty() ? NULL : &(s->_executionStack.back());
332 }
333 
addKernelCallToExecStack(EngineState * s,int kernelCallNr,int kernelSubCallNr,int argc,reg_t * argv)334 static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int kernelSubCallNr, int argc, reg_t *argv) {
335 	// Add stack frame to indicate we're executing a callk.
336 	// This is useful in debugger backtraces if this
337 	// kernel function calls a script itself.
338 	ExecStack xstack(NULL_REG, NULL_REG, argv + argc, argc, argv - 1, kUninitializedSegment, make_reg32(0, 0),
339 						-1, kernelCallNr, kernelSubCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL);
340 	s->_executionStack.push_back(xstack);
341 }
342 
callKernelFunc(EngineState * s,int kernelCallNr,int argc)343 static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
344 	Kernel *kernel = g_sci->getKernel();
345 
346 	if (kernelCallNr >= (int)kernel->_kernelFuncs.size())
347 		error("Invalid kernel function 0x%x requested", kernelCallNr);
348 
349 	const KernelFunction &kernelCall = kernel->_kernelFuncs[kernelCallNr];
350 	reg_t *argv = s->xs->sp + 1;
351 
352 	if (kernelCall.signature
353 			&& !kernel->signatureMatch(kernelCall.signature, argc, argv)) {
354 		// signature mismatch, check if a workaround is available
355 		SciCallOrigin originReply;
356 		SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kernelCall.workarounds, &originReply);
357 		switch (solution.type) {
358 		case WORKAROUND_NONE: {
359 			Common::String signatureDetailsStr;
360 			kernel->signatureDebug(signatureDetailsStr, kernelCall.signature, argc, argv);
361 			error("\n%s[VM] k%s[%x]: signature mismatch in %s", signatureDetailsStr.c_str(), kernelCall.name, kernelCallNr, originReply.toString().c_str());
362 			break;
363 			}
364 		case WORKAROUND_IGNORE: // don't do kernel call, leave acc alone
365 			return;
366 		case WORKAROUND_STILLCALL: // call kernel anyway
367 			break;
368 		case WORKAROUND_FAKE: // don't do kernel call, fake acc
369 			s->r_acc = make_reg(0, solution.value);
370 			return;
371 		default:
372 			error("unknown workaround type");
373 		}
374 	}
375 
376 
377 	// Call kernel function
378 	if (!kernelCall.subFunctionCount) {
379 		argv[-1] = make_reg(0, argc); // The first argument is argc
380 		addKernelCallToExecStack(s, kernelCallNr, -1, argc, argv);
381 		s->r_acc = kernelCall.function(s, argc, argv);
382 
383 		if (g_sci->checkKernelBreakpoint(kernelCall.name))
384 			logKernelCall(&kernelCall, NULL, s, argc, argv, s->r_acc);
385 	} else {
386 		// Sub-functions available, check signature and call that one directly
387 		if (argc < 1)
388 			error("[VM] k%s[%x]: no subfunction ID parameter given", kernelCall.name, kernelCallNr);
389 		if (argv[0].isPointer())
390 			error("[VM] k%s[%x]: given subfunction ID is actually a pointer", kernelCall.name, kernelCallNr);
391 
392 #ifdef ENABLE_SCI32
393 		// The Windows version of kShowMovie has subops, but the subop number
394 		// is put in the second parameter in SCI2.1+, even though every other
395 		// kcall with subops puts the subop in the first parameter. To allow use
396 		// of the normal subops system, we swap the arguments so the subop
397 		// number is in the usual place.
398 		if (getSciVersion() > SCI_VERSION_2 &&
399 			g_sci->getPlatform() == Common::kPlatformWindows &&
400 			strcmp(kernelCall.name, "ShowMovie") == 0) {
401 			assert(argc > 1);
402 			SWAP(argv[0], argv[1]);
403 		}
404 #endif
405 
406 		const uint16 subId = argv[0].toUint16();
407 		// Skip over subfunction-id
408 		argc--;
409 		argv++;
410 		if (subId >= kernelCall.subFunctionCount)
411 			error("[VM] k%s: subfunction ID %d requested, but not available", kernelCall.name, subId);
412 		const KernelSubFunction &kernelSubCall = kernelCall.subFunctions[subId];
413 		if (kernelSubCall.signature && !kernel->signatureMatch(kernelSubCall.signature, argc, argv)) {
414 			// Signature mismatch
415 			SciCallOrigin originReply;
416 			SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kernelSubCall.workarounds, &originReply);
417 			switch (solution.type) {
418 			case WORKAROUND_NONE: {
419 				Common::String signatureDetailsStr;
420 				kernel->signatureDebug(signatureDetailsStr, kernelSubCall.signature, argc, argv);
421 				int callNameLen = strlen(kernelCall.name);
422 				if (strncmp(kernelCall.name, kernelSubCall.name, callNameLen) == 0) {
423 					const char *subCallName = kernelSubCall.name + callNameLen;
424 					error("\n%s[VM] k%s(%s): signature mismatch in %s",
425 						signatureDetailsStr.c_str(), kernelCall.name, subCallName,
426 						originReply.toString().c_str());
427 				}
428 				error("\n%s[VM] k%s: signature mismatch in %s",
429 					signatureDetailsStr.c_str(), kernelSubCall.name,
430 					originReply.toString().c_str());
431 				break;
432 			}
433 			case WORKAROUND_IGNORE: // don't do kernel call, leave acc alone
434 				return;
435 			case WORKAROUND_STILLCALL: // call kernel anyway
436 				break;
437 			case WORKAROUND_FAKE: // don't do kernel call, fake acc
438 				s->r_acc = make_reg(0, solution.value);
439 				return;
440 			default:
441 				error("unknown workaround type");
442 			}
443 		}
444 		if (!kernelSubCall.function)
445 			error("[VM] k%s: subfunction ID %d requested, but not available", kernelCall.name, subId);
446 		argv[-1] = make_reg(0, argc); // The first argument is argc
447 		addKernelCallToExecStack(s, kernelCallNr, subId, argc, argv);
448 		s->r_acc = kernelSubCall.function(s, argc, argv);
449 
450 		if (g_sci->checkKernelBreakpoint(kernelSubCall.name))
451 			logKernelCall(&kernelCall, &kernelSubCall, s, argc, argv, s->r_acc);
452 	}
453 
454 	// Remove callk stack frame again, if there's still an execution stack
455 	if (s->_executionStack.begin() != s->_executionStack.end())
456 		s->_executionStack.pop_back();
457 }
458 
readPMachineInstruction(const byte * src,byte & extOpcode,int16 opparams[4])459 int readPMachineInstruction(const byte *src, byte &extOpcode, int16 opparams[4]) {
460 	uint offset = 0;
461 	extOpcode = src[offset++]; // Get "extended" opcode (lower bit has special meaning)
462 	const byte opcode = extOpcode >> 1;	// get the actual opcode
463 
464 	memset(opparams, 0, 4*sizeof(int16));
465 
466 	for (int i = 0; g_sci->_opcode_formats[opcode][i]; ++i) {
467 		//debugN("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opcode, temp);
468 		assert(i < 3);
469 		switch (g_sci->_opcode_formats[opcode][i]) {
470 
471 		case Script_Byte:
472 			opparams[i] = src[offset++];
473 			break;
474 		case Script_SByte:
475 			opparams[i] = (int8)src[offset++];
476 			break;
477 
478 		case Script_Word:
479 			opparams[i] = READ_SCI11ENDIAN_UINT16(src + offset);
480 			offset += 2;
481 			break;
482 		case Script_SWord:
483 			opparams[i] = (int16)READ_SCI11ENDIAN_UINT16(src + offset);
484 			offset += 2;
485 			break;
486 
487 		case Script_Variable:
488 		case Script_Property:
489 
490 		case Script_Local:
491 		case Script_Temp:
492 		case Script_Global:
493 		case Script_Param:
494 
495 		case Script_Offset:
496 			if (extOpcode & 1) {
497 				opparams[i] = src[offset++];
498 			} else {
499 				opparams[i] = READ_SCI11ENDIAN_UINT16(src + offset);
500 				offset += 2;
501 			}
502 			break;
503 
504 		case Script_SVariable:
505 		case Script_SRelative:
506 			if (extOpcode & 1) {
507 				opparams[i] = (int8)src[offset++];
508 			} else {
509 				opparams[i] = (int16)READ_SCI11ENDIAN_UINT16(src + offset);
510 				offset += 2;
511 			}
512 			break;
513 
514 		case Script_None:
515 		case Script_End:
516 			break;
517 
518 		case Script_Invalid:
519 		default:
520 			error("opcode %02x: Invalid", extOpcode);
521 		}
522 	}
523 
524 	// Special handling of the op_line opcode
525 	if (opcode == op_pushSelf) {
526 		// Compensate for a bug in non-Sierra compilers, which seem to generate
527 		// pushSelf instructions with the low bit set. This makes the following
528 		// heuristic fail and leads to endless loops and crashes. Our
529 		// interpretation of this seems correct, as other SCI tools, like for
530 		// example SCI Viewer, have issues with these scripts (e.g. script 999
531 		// in Circus Quest). Fixes bug #3038686.
532 		if (!(extOpcode & 1) || g_sci->getGameId() == GID_FANMADE) {
533 			// op_pushSelf: no adjustment necessary
534 		} else {
535 			// Debug opcode op_file, skip null-terminated string (file name)
536 			while (src[offset++]) {}
537 		}
538 	}
539 
540 	return offset;
541 }
542 
findOffset(const int16 relOffset,const Script * scr,const uint32 pcOffset)543 uint32 findOffset(const int16 relOffset, const Script *scr, const uint32 pcOffset) {
544 	uint32 offset;
545 
546 	switch (g_sci->_features->detectLofsType()) {
547 	case SCI_VERSION_0_EARLY:
548 		offset = (uint16)pcOffset + relOffset;
549 		break;
550 	case SCI_VERSION_1_MIDDLE:
551 		offset = relOffset;
552 		break;
553 	case SCI_VERSION_1_1:
554 		offset = relOffset + scr->getHeapOffset();
555 		break;
556 #ifdef ENABLE_SCI32
557 	case SCI_VERSION_3:
558 		// In theory this can break if the variant with a one-byte argument is
559 		// used. For now, assume it doesn't happen.
560 		offset = scr->relocateOffsetSci3(pcOffset - 2);
561 		break;
562 #endif
563 	default:
564 		error("Unknown lofs type");
565 	}
566 
567 	return offset;
568 }
569 
run_vm(EngineState * s)570 void run_vm(EngineState *s) {
571 	assert(s);
572 
573 	int temp;
574 	reg_t r_temp; // Temporary register
575 	StackPtr s_temp; // Temporary stack pointer
576 	int16 opparams[4]; // opcode parameters
577 
578 	s->r_rest = 0;	// &rest adjusts the parameter count by this value
579 	// Current execution data:
580 	s->xs = &(s->_executionStack.back());
581 	ExecStack *xs_new = NULL;
582 	Object *obj = s->_segMan->getObject(s->xs->objp);
583 	Script *scr = 0;
584 	Script *local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment);
585 	int old_executionStackBase = s->executionStackBase;
586 	// Used to detect the stack bottom, for "physical" returns
587 
588 	if (!local_script)
589 		error("run_vm(): program counter gone astray (local_script pointer is null)");
590 
591 	s->executionStackBase = s->_executionStack.size() - 1;
592 
593 	s->variablesSegment[VAR_TEMP] = s->variablesSegment[VAR_PARAM] = s->_segMan->findSegmentByType(SEG_TYPE_STACK);
594 	s->variablesBase[VAR_TEMP] = s->variablesBase[VAR_PARAM] = s->stack_base;
595 
596 	s->_executionStackPosChanged = true; // Force initialization
597 
598 #ifdef ABORT_ON_INFINITE_LOOP
599 	byte prevOpcode = 0xFF;
600 #endif
601 
602 	while (1) {
603 		int var_type; // See description below
604 		int var_number;
605 
606 		g_sci->_debugState.old_pc_offset = s->xs->addr.pc.getOffset();
607 		g_sci->_debugState.old_sp = s->xs->sp;
608 
609 		if (s->abortScriptProcessing != kAbortNone)
610 			return; // Stop processing
611 
612 		if (s->_executionStackPosChanged) {
613 			scr = s->_segMan->getScriptIfLoaded(s->xs->addr.pc.getSegment());
614 			if (!scr)
615 				error("No script in segment %d",  s->xs->addr.pc.getSegment());
616 			s->xs = &(s->_executionStack.back());
617 			s->_executionStackPosChanged = false;
618 
619 			obj = s->_segMan->getObject(s->xs->objp);
620 			local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment);
621 			if (!local_script) {
622 				error("Could not find local script from segment %x", s->xs->local_segment);
623 			} else {
624 				s->variablesSegment[VAR_LOCAL] = local_script->getLocalsSegment();
625 				s->variablesBase[VAR_LOCAL] = s->variables[VAR_LOCAL] = local_script->getLocalsBegin();
626 				s->variablesMax[VAR_LOCAL] = local_script->getLocalsCount();
627 				s->variablesMax[VAR_TEMP] = s->xs->sp - s->xs->fp;
628 				s->variablesMax[VAR_PARAM] = s->xs->argc + 1;
629 			}
630 			s->variables[VAR_TEMP] = s->xs->fp;
631 			s->variables[VAR_PARAM] = s->xs->variables_argp;
632 		}
633 
634 		if (s->abortScriptProcessing != kAbortNone)
635 			return; // Stop processing
636 
637 		g_sci->checkAddressBreakpoint(s->xs->addr.pc);
638 
639 		// Debug if this has been requested:
640 		// TODO: re-implement sci_debug_flags
641 		if (g_sci->_debugState.debugging /* sci_debug_flags*/) {
642 			g_sci->scriptDebug();
643 			g_sci->_debugState.breakpointWasHit = false;
644 		}
645 		Console *con = g_sci->getSciDebugger();
646 		con->onFrame();
647 
648 		if (s->xs->sp < s->xs->fp)
649 			error("run_vm(): stack underflow, sp: %04x:%04x, fp: %04x:%04x",
650 			PRINT_REG(*s->xs->sp), PRINT_REG(*s->xs->fp));
651 
652 		s->variablesMax[VAR_TEMP] = s->xs->sp - s->xs->fp;
653 
654 		if (s->xs->addr.pc.getOffset() >= scr->getBufSize())
655 			error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d",
656 			s->xs->addr.pc.getOffset(), scr->getBufSize());
657 
658 		// Get opcode
659 		byte extOpcode;
660 		s->xs->addr.pc.incOffset(readPMachineInstruction(scr->getBuf(s->xs->addr.pc.getOffset()), extOpcode, opparams));
661 		const byte opcode = extOpcode >> 1;
662 		//debug("%s: %d, %d, %d, %d, acc = %04x:%04x, script %d, local script %d", opcodeNames[opcode], opparams[0], opparams[1], opparams[2], opparams[3], PRINT_REG(s->r_acc), scr->getScriptNumber(), local_script->getScriptNumber());
663 
664 #ifdef ABORT_ON_INFINITE_LOOP
665 		if (prevOpcode != 0xFF) {
666 			if (prevOpcode == op_eq_  || prevOpcode == op_ne_  ||
667 				prevOpcode == op_gt_  || prevOpcode == op_ge_  ||
668 				prevOpcode == op_lt_  || prevOpcode == op_le_  ||
669 				prevOpcode == op_ugt_ || prevOpcode == op_uge_ ||
670 				prevOpcode == op_ult_ || prevOpcode == op_ule_) {
671 				if (opcode == op_jmp)
672 					error("Infinite loop detected in script %d", scr->getScriptNumber());
673 			}
674 		}
675 
676 		prevOpcode = opcode;
677 #endif
678 
679 		switch (opcode) {
680 
681 		case op_bnot: // 0x00 (00)
682 			// Binary not
683 			s->r_acc = make_reg(0, 0xffff ^ s->r_acc.requireUint16());
684 			break;
685 
686 		case op_add: // 0x01 (01)
687 			s->r_acc = POP32() + s->r_acc;
688 			break;
689 
690 		case op_sub: // 0x02 (02)
691 			s->r_acc = POP32() - s->r_acc;
692 			break;
693 
694 		case op_mul: // 0x03 (03)
695 			s->r_acc = POP32() * s->r_acc;
696 			break;
697 
698 		case op_div: // 0x04 (04)
699 			// we check for division by 0 inside the custom reg_t division operator
700 			s->r_acc = POP32() / s->r_acc;
701 			break;
702 
703 		case op_mod: // 0x05 (05)
704 			// we check for division by 0 inside the custom reg_t modulo operator
705 			s->r_acc = POP32() % s->r_acc;
706 			break;
707 
708 		case op_shr: // 0x06 (06)
709 			// Shift right logical
710 			s->r_acc = POP32() >> s->r_acc;
711 			break;
712 
713 		case op_shl: // 0x07 (07)
714 			// Shift left logical
715 			s->r_acc = POP32() << s->r_acc;
716 			break;
717 
718 		case op_xor: // 0x08 (08)
719 			s->r_acc = POP32() ^ s->r_acc;
720 			break;
721 
722 		case op_and: // 0x09 (09)
723 			s->r_acc = POP32() & s->r_acc;
724 			break;
725 
726 		case op_or: // 0x0a (10)
727 			s->r_acc = POP32() | s->r_acc;
728 			break;
729 
730 		case op_neg:	// 0x0b (11)
731 			s->r_acc = make_reg(0, -s->r_acc.requireSint16());
732 			break;
733 
734 		case op_not: // 0x0c (12)
735 			s->r_acc = make_reg(0, !(s->r_acc.getOffset() || s->r_acc.getSegment()));
736 			// Must allow pointers to be negated, as this is used for checking whether objects exist
737 			break;
738 
739 		case op_eq_: // 0x0d (13)
740 			s->r_prev = s->r_acc;
741 			s->r_acc  = make_reg(0, POP32() == s->r_acc);
742 			break;
743 
744 		case op_ne_: // 0x0e (14)
745 			s->r_prev = s->r_acc;
746 			s->r_acc  = make_reg(0, POP32() != s->r_acc);
747 			break;
748 
749 		case op_gt_: // 0x0f (15)
750 			s->r_prev = s->r_acc;
751 			s->r_acc  = make_reg(0, POP32() > s->r_acc);
752 			break;
753 
754 		case op_ge_: // 0x10 (16)
755 			s->r_prev = s->r_acc;
756 			s->r_acc  = make_reg(0, POP32() >= s->r_acc);
757 			break;
758 
759 		case op_lt_: // 0x11 (17)
760 			s->r_prev = s->r_acc;
761 			s->r_acc  = make_reg(0, POP32() < s->r_acc);
762 			break;
763 
764 		case op_le_: // 0x12 (18)
765 			s->r_prev = s->r_acc;
766 			s->r_acc  = make_reg(0, POP32() <= s->r_acc);
767 			break;
768 
769 		case op_ugt_: // 0x13 (19)
770 			// > (unsigned)
771 			s->r_prev = s->r_acc;
772 			s->r_acc  = make_reg(0, POP32().gtU(s->r_acc));
773 			break;
774 
775 		case op_uge_: // 0x14 (20)
776 			// >= (unsigned)
777 			s->r_prev = s->r_acc;
778 			s->r_acc  = make_reg(0, POP32().geU(s->r_acc));
779 			break;
780 
781 		case op_ult_: // 0x15 (21)
782 			// < (unsigned)
783 			s->r_prev = s->r_acc;
784 			s->r_acc  = make_reg(0, POP32().ltU(s->r_acc));
785 			break;
786 
787 		case op_ule_: // 0x16 (22)
788 			// <= (unsigned)
789 			s->r_prev = s->r_acc;
790 			s->r_acc  = make_reg(0, POP32().leU(s->r_acc));
791 			break;
792 
793 		case op_bt: // 0x17 (23)
794 			// Branch relative if true
795 			if (s->r_acc.getOffset() || s->r_acc.getSegment())
796 				s->xs->addr.pc.incOffset(opparams[0]);
797 
798 			if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize())
799 				error("[VM] op_bt: request to jump past the end of script %d (offset %d, script is %d bytes)",
800 					local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize());
801 			break;
802 
803 		case op_bnt: // 0x18 (24)
804 			// Branch relative if not true
805 			if (!(s->r_acc.getOffset() || s->r_acc.getSegment()))
806 				s->xs->addr.pc.incOffset(opparams[0]);
807 
808 			if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize())
809 				error("[VM] op_bnt: request to jump past the end of script %d (offset %d, script is %d bytes)",
810 					local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize());
811 			break;
812 
813 		case op_jmp: // 0x19 (25)
814 			s->xs->addr.pc.incOffset(opparams[0]);
815 
816 			if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize())
817 				error("[VM] op_jmp: request to jump past the end of script %d (offset %d, script is %d bytes)",
818 					local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize());
819 			break;
820 
821 		case op_ldi: // 0x1a (26)
822 			// Load data immediate
823 			s->r_acc = make_reg(0, opparams[0]);
824 			break;
825 
826 		case op_push: // 0x1b (27)
827 			// Push to stack
828 			PUSH32(s->r_acc);
829 			break;
830 
831 		case op_pushi: // 0x1c (28)
832 			// Push immediate
833 			PUSH(opparams[0]);
834 			break;
835 
836 		case op_toss: // 0x1d (29)
837 			// TOS (Top Of Stack) subtract
838 			s->xs->sp--;
839 			break;
840 
841 		case op_dup: // 0x1e (30)
842 			// Duplicate TOD (Top Of Stack) element
843 			r_temp = s->xs->sp[-1];
844 			PUSH32(r_temp);
845 			break;
846 
847 		case op_link: // 0x1f (31)
848 			// We shouldn't initialize temp variables at all
849 			//  We put special segment 0xFFFF in there, so that uninitialized reads can get detected
850 			for (int i = 0; i < opparams[0]; i++)
851 				s->xs->sp[i] = make_reg(kUninitializedSegment, 0);
852 
853 			s->xs->sp += opparams[0];
854 			break;
855 
856 		case op_call: { // 0x20 (32)
857 			// Call a script subroutine
858 			int argc = (opparams[1] >> 1) // Given as offset, but we need count
859 			           + 1 + s->r_rest;
860 			StackPtr call_base = s->xs->sp - argc;
861 
862 			uint32 localCallOffset = s->xs->addr.pc.getOffset() + opparams[0];
863 
864 			int final_argc = (call_base->requireUint16()) + s->r_rest;
865 			call_base[0] = make_reg(0, final_argc); // The first argument is argc
866 			ExecStack xstack(s->xs->objp, s->xs->objp, s->xs->sp,
867 							final_argc, call_base,
868 							s->xs->local_segment, make_reg32(s->xs->addr.pc.getSegment(), localCallOffset),
869 							NULL_SELECTOR, -1, -1, -1, localCallOffset, s->_executionStack.size() - 1,
870 							EXEC_STACK_TYPE_CALL);
871 
872 			s->_executionStack.push_back(xstack);
873 			xs_new = &(s->_executionStack.back());
874 
875 			s->r_rest = 0; // Used up the &rest adjustment
876 			s->xs->sp = call_base;
877 
878 			s->_executionStackPosChanged = true;
879 			break;
880 		}
881 
882 		case op_callk: { // 0x21 (33)
883 			// Run the garbage collector, if needed
884 			if (s->gcCountDown-- <= 0) {
885 				s->gcCountDown = s->scriptGCInterval;
886 				run_gc(s);
887 			}
888 
889 			// Call kernel function
890 			s->xs->sp -= (opparams[1] >> 1) + 1;
891 
892 			bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
893 			if (!oldScriptHeader)
894 				s->xs->sp -= s->r_rest;
895 
896 			int argc = s->xs->sp[0].requireUint16();
897 
898 			if (!oldScriptHeader)
899 				argc += s->r_rest;
900 
901 			callKernelFunc(s, opparams[0], argc);
902 
903 			if (!oldScriptHeader)
904 				s->r_rest = 0;
905 
906 			// Calculate xs again: The kernel function might
907 			// have spawned a new VM
908 
909 			xs_new = &(s->_executionStack.back());
910 			s->_executionStackPosChanged = true;
911 
912 			// If a game is being loaded, stop processing
913 			if (s->abortScriptProcessing != kAbortNone)
914 				return; // Stop processing
915 
916 			break;
917 		}
918 
919 		case op_callb: // 0x22 (34)
920 			// Call base script
921 			temp = ((opparams[1] >> 1) + s->r_rest + 1);
922 			s_temp = s->xs->sp;
923 			s->xs->sp -= temp;
924 
925 			s->xs->sp[0].incOffset(s->r_rest);
926 			xs_new = execute_method(s, 0, opparams[0], s_temp, s->xs->objp,
927 									s->xs->sp[0].getOffset(), s->xs->sp);
928 			s->r_rest = 0; // Used up the &rest adjustment
929 			if (xs_new)    // in case of error, keep old stack
930 				s->_executionStackPosChanged = true;
931 			break;
932 
933 		case op_calle: // 0x23 (35)
934 			// Call external script
935 			temp = ((opparams[2] >> 1) + s->r_rest + 1);
936 			s_temp = s->xs->sp;
937 			s->xs->sp -= temp;
938 
939 			s->xs->sp[0].incOffset(s->r_rest);
940 			xs_new = execute_method(s, opparams[0], opparams[1], s_temp, s->xs->objp,
941 									s->xs->sp[0].getOffset(), s->xs->sp);
942 			s->r_rest = 0; // Used up the &rest adjustment
943 			if (xs_new)  // in case of error, keep old stack
944 				s->_executionStackPosChanged = true;
945 			break;
946 
947 		case op_ret: // 0x24 (36)
948 			// Return from an execution loop started by call, calle, callb, send, self or super
949 			do {
950 				StackPtr old_sp2 = s->xs->sp;
951 				StackPtr old_fp = s->xs->fp;
952 				ExecStack *old_xs = &(s->_executionStack.back());
953 
954 				if ((int)s->_executionStack.size() - 1 == s->executionStackBase) { // Have we reached the base?
955 					s->executionStackBase = old_executionStackBase; // Restore stack base
956 
957 					s->_executionStack.pop_back();
958 
959 					s->_executionStackPosChanged = true;
960 					return; // "Hard" return
961 				}
962 
963 				if (old_xs->type == EXEC_STACK_TYPE_VARSELECTOR) {
964 					// varselector access?
965 					reg_t *var = old_xs->getVarPointer(s->_segMan);
966 					if (old_xs->argc) { // write?
967 						*var = old_xs->variables_argp[1];
968 
969 #ifdef ENABLE_SCI32
970 						updateInfoFlagViewVisible(s->_segMan->getObject(old_xs->addr.varp.obj), old_xs->addr.varp.varindex);
971 #endif
972 					} else // No, read
973 						s->r_acc = *var;
974 				}
975 
976 				// Not reached the base, so let's do a soft return
977 				s->_executionStack.pop_back();
978 				s->_executionStackPosChanged = true;
979 				s->xs = &(s->_executionStack.back());
980 
981 				if (s->xs->sp == CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
982 				        || s->xs->type != EXEC_STACK_TYPE_CALL) {
983 					s->xs->sp = old_sp2;
984 					s->xs->fp = old_fp;
985 				}
986 
987 			} while (s->xs->type == EXEC_STACK_TYPE_VARSELECTOR);
988 			// Iterate over all varselector accesses
989 			s->_executionStackPosChanged = true;
990 			xs_new = s->xs;
991 
992 			break;
993 
994 		case op_send: // 0x25 (37)
995 			// Send for one or more selectors
996 			s_temp = s->xs->sp;
997 			s->xs->sp -= ((opparams[0] >> 1) + s->r_rest); // Adjust stack
998 
999 			s->xs->sp[1].incOffset(s->r_rest);
1000 			xs_new = send_selector(s, s->r_acc, s->r_acc, s_temp,
1001 									(int)(opparams[0] >> 1) + (uint16)s->r_rest, s->xs->sp);
1002 
1003 			if (xs_new && xs_new != s->xs)
1004 				s->_executionStackPosChanged = true;
1005 
1006 			s->r_rest = 0;
1007 
1008 			break;
1009 
1010 		case op_info: // (38)
1011 			if (getSciVersion() < SCI_VERSION_3)
1012 				error("Dummy opcode 0x%x called", opcode);	// should never happen
1013 
1014 			if (!(extOpcode & 1))
1015 				s->r_acc = obj->getInfoSelector();
1016 			else
1017 				PUSH32(obj->getInfoSelector());
1018 			break;
1019 
1020 		case op_superP: // (39)
1021 			if (getSciVersion() < SCI_VERSION_3)
1022 				error("Dummy opcode 0x%x called", opcode);	// should never happen
1023 
1024 			if (!(extOpcode & 1))
1025 				s->r_acc = obj->getSuperClassSelector();
1026 			else
1027 				PUSH32(obj->getSuperClassSelector());
1028 			break;
1029 
1030 		case op_class: // 0x28 (40)
1031 			// Get class address
1032 			s->r_acc = s->_segMan->getClassAddress((unsigned)opparams[0], SCRIPT_GET_LOCK,
1033 											s->xs->addr.pc.getSegment());
1034 			break;
1035 
1036 		case 0x29: // (41)
1037 			error("Dummy opcode 0x%x called", opcode);	// should never happen
1038 			break;
1039 
1040 		case op_self: // 0x2a (42)
1041 			// Send to self
1042 			s_temp = s->xs->sp;
1043 			s->xs->sp -= ((opparams[0] >> 1) + s->r_rest); // Adjust stack
1044 
1045 			s->xs->sp[1].incOffset(s->r_rest);
1046 			xs_new = send_selector(s, s->xs->objp, s->xs->objp,
1047 									s_temp, (int)(opparams[0] >> 1) + (uint16)s->r_rest,
1048 									s->xs->sp);
1049 
1050 			if (xs_new && xs_new != s->xs)
1051 				s->_executionStackPosChanged = true;
1052 
1053 			s->r_rest = 0;
1054 			break;
1055 
1056 		case op_super: // 0x2b (43)
1057 			// Send to any class
1058 			r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc.getSegment());
1059 
1060 			if (!r_temp.isPointer())
1061 				error("[VM]: Invalid superclass in object");
1062 			else {
1063 				// SCI3 sets r_acc to whatever was in EAX at the start of a
1064 				// send. In the case of a super call this is the object ID of
1065 				// the superclass, as determined by the interpreter, rather than
1066 				// by the game scripts
1067 				if (getSciVersion() == SCI_VERSION_3) {
1068 					s->r_acc = r_temp;
1069 				}
1070 
1071 				s_temp = s->xs->sp;
1072 				s->xs->sp -= ((opparams[1] >> 1) + s->r_rest); // Adjust stack
1073 
1074 				s->xs->sp[1].incOffset(s->r_rest);
1075 				xs_new = send_selector(s, r_temp, s->xs->objp, s_temp,
1076 										(int)(opparams[1] >> 1) + (uint16)s->r_rest,
1077 										s->xs->sp);
1078 
1079 				if (xs_new && xs_new != s->xs)
1080 					s->_executionStackPosChanged = true;
1081 
1082 				s->r_rest = 0;
1083 			}
1084 
1085 			break;
1086 
1087 		case op_rest: // 0x2c (44)
1088 			// Pushes all or part of the parameter variable list on the stack
1089 			// Index 0 is argc, so normally this will be called as &rest 1 to
1090 			// forward all the arguments.
1091 			temp = (uint16) opparams[0]; // First argument
1092 			s->r_rest = MAX<int16>(s->xs->argc - temp + 1, 0); // +1 because temp counts the paramcount while argc doesn't
1093 
1094 			for (; temp <= s->xs->argc; temp++)
1095 				PUSH32(s->xs->variables_argp[temp]);
1096 
1097 			break;
1098 
1099 		case op_lea: // 0x2d (45)
1100 			// Load Effective Address
1101 			temp = (uint16) opparams[0] >> 1;
1102 			var_number = temp & 0x03; // Get variable type
1103 
1104 			// Get variable block offset
1105 			r_temp.setSegment(s->variablesSegment[var_number]);
1106 			r_temp.setOffset(s->variables[var_number] - s->variablesBase[var_number]);
1107 
1108 			if (temp & 0x08)  // Add accumulator offset if requested
1109 				r_temp.incOffset(s->r_acc.requireSint16());
1110 
1111 			r_temp.incOffset(opparams[1]);  // Add index
1112 			r_temp.setOffset(r_temp.getOffset() * 2); // variables are 16 bit
1113 			// That's the immediate address now
1114 			s->r_acc = r_temp;
1115 			break;
1116 
1117 
1118 		case op_selfID: // 0x2e (46)
1119 			// Get 'self' identity
1120 			s->r_acc = s->xs->objp;
1121 			break;
1122 
1123 		case 0x2f: // (47)
1124 			error("Dummy opcode 0x%x called", opcode);	// should never happen
1125 			break;
1126 
1127 		case op_pprev: // 0x30 (48)
1128 			// Pushes the value of the prev register, set by the last comparison
1129 			// bytecode (eq?, lt?, etc.), on the stack
1130 			PUSH32(s->r_prev);
1131 			break;
1132 
1133 		case op_pToa: // 0x31 (49)
1134 			// Property To Accumulator
1135 			if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
1136 				debugPropertyAccess(obj, s->xs->objp, opparams[0],
1137 				                    validate_property(s, obj, opparams[0]), NULL_REG,
1138 				                    s->_segMan, BREAK_SELECTORREAD);
1139 			}
1140 			s->r_acc = validate_property(s, obj, opparams[0]);
1141 			break;
1142 
1143 		case op_aTop: // 0x32 (50)
1144 			{
1145 			// Accumulator To Property
1146 			reg_t &opProperty = validate_property(s, obj, opparams[0]);
1147 			if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
1148 				debugPropertyAccess(obj, s->xs->objp, opparams[0],
1149 				                    opProperty, s->r_acc,
1150 				                    s->_segMan, BREAK_SELECTORWRITE);
1151 			}
1152 
1153 			opProperty = s->r_acc;
1154 #ifdef ENABLE_SCI32
1155 			updateInfoFlagViewVisible(obj, opparams[0], true);
1156 #endif
1157 			break;
1158 		}
1159 
1160 		case op_pTos: // 0x33 (51)
1161 			{
1162 			// Property To Stack
1163 			reg_t value = validate_property(s, obj, opparams[0]);
1164 			if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
1165 				debugPropertyAccess(obj, s->xs->objp, opparams[0],
1166 				                    value, NULL_REG,
1167 				                    s->_segMan, BREAK_SELECTORREAD);
1168 			}
1169 			PUSH32(value);
1170 			break;
1171 		}
1172 
1173 		case op_sTop: // 0x34 (52)
1174 			{
1175 			// Stack To Property
1176 			reg_t newValue = POP32();
1177 			reg_t &opProperty = validate_property(s, obj, opparams[0]);
1178 			if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
1179 				debugPropertyAccess(obj, s->xs->objp, opparams[0],
1180 				                    opProperty, newValue,
1181 				                    s->_segMan, BREAK_SELECTORWRITE);
1182 			}
1183 			opProperty = newValue;
1184 #ifdef ENABLE_SCI32
1185 			updateInfoFlagViewVisible(obj, opparams[0], true);
1186 #endif
1187 			break;
1188 		}
1189 
1190 		case op_ipToa: // 0x35 (53)
1191 		case op_dpToa: // 0x36 (54)
1192 		case op_ipTos: // 0x37 (55)
1193 		case op_dpTos: // 0x38 (56)
1194 			{
1195 			// Increment/decrement a property and copy to accumulator,
1196 			// or push to stack
1197 			reg_t &opProperty = validate_property(s, obj, opparams[0]);
1198 			reg_t oldValue = opProperty;
1199 
1200 			if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
1201 				debugPropertyAccess(obj, s->xs->objp, opparams[0],
1202 				                    oldValue, NULL_REG,
1203 				                    s->_segMan, BREAK_SELECTORREAD);
1204 			}
1205 
1206 			if (opcode & 1)
1207 				opProperty += 1;
1208 			else
1209 				opProperty -= 1;
1210 
1211 			if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
1212 				debugPropertyAccess(obj, s->xs->objp, opparams[0],
1213 				                    oldValue, opProperty,
1214 				                    s->_segMan, BREAK_SELECTORWRITE);
1215 			}
1216 
1217 #ifdef ENABLE_SCI32
1218 			updateInfoFlagViewVisible(obj, opparams[0], true);
1219 #endif
1220 			if (opcode == op_ipToa || opcode == op_dpToa)
1221 				s->r_acc = opProperty;
1222 			else
1223 				PUSH32(opProperty);
1224 			break;
1225 		}
1226 
1227 		case op_lofsa: // 0x39 (57)
1228 		case op_lofss: { // 0x3a (58)
1229 			// Load offset to accumulator or push to stack
1230 
1231 			r_temp.setSegment(s->xs->addr.pc.getSegment());
1232 			r_temp.setOffset(findOffset(opparams[0], local_script, s->xs->addr.pc.getOffset()));
1233 			if (r_temp.getOffset() >= scr->getBufSize())
1234 				error("VM: lofsa/lofss operation overflowed: %04x:%04x beyond end"
1235 						  " of script (at %04x)", PRINT_REG(r_temp), scr->getBufSize());
1236 
1237 			if (opcode == op_lofsa)
1238 				s->r_acc = r_temp;
1239 			else
1240 				PUSH32(r_temp);
1241 			break;
1242 		}
1243 
1244 		case op_push0: // 0x3b (59)
1245 			PUSH(0);
1246 			break;
1247 
1248 		case op_push1: // 0x3c (60)
1249 			PUSH(1);
1250 			break;
1251 
1252 		case op_push2: // 0x3d (61)
1253 			PUSH(2);
1254 			break;
1255 
1256 		case op_pushSelf: // 0x3e (62)
1257 			// Compensate for a bug in non-Sierra compilers, which seem to generate
1258 			// pushSelf instructions with the low bit set. This makes the following
1259 			// heuristic fail and leads to endless loops and crashes. Our
1260 			// interpretation of this seems correct, as other SCI tools, like for
1261 			// example SCI Viewer, have issues with these scripts (e.g. script 999
1262 			// in Circus Quest). Fixes bug #3038686.
1263 			if (!(extOpcode & 1) || g_sci->getGameId() == GID_FANMADE) {
1264 				PUSH32(s->xs->objp);
1265 			} else {
1266 				// Debug opcode op_file
1267 			}
1268 			break;
1269 
1270 		case op_line: // 0x3f (63)
1271 			// Debug opcode (line number)
1272 			//debug("Script %d, line %d", scr->getScriptNumber(), opparams[0]);
1273 			break;
1274 
1275 		case op_lag: // 0x40 (64)
1276 		case op_lal: // 0x41 (65)
1277 		case op_lat: // 0x42 (66)
1278 		case op_lap: // 0x43 (67)
1279 			// Load global, local, temp or param variable into the accumulator
1280 		case op_lagi: // 0x48 (72)
1281 		case op_lali: // 0x49 (73)
1282 		case op_lati: // 0x4a (74)
1283 		case op_lapi: // 0x4b (75)
1284 			// Same as the 4 ones above, except that the accumulator is used as
1285 			// an additional index
1286 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1287 			var_number = opparams[0] + (opcode >= op_lagi ? s->r_acc.requireSint16() : 0);
1288 			s->r_acc = read_var(s, var_type, var_number);
1289 			break;
1290 
1291 		case op_lsg: // 0x44 (68)
1292 		case op_lsl: // 0x45 (69)
1293 		case op_lst: // 0x46 (70)
1294 		case op_lsp: // 0x47 (71)
1295 			// Load global, local, temp or param variable into the stack
1296 		case op_lsgi: // 0x4c (76)
1297 		case op_lsli: // 0x4d (77)
1298 		case op_lsti: // 0x4e (78)
1299 		case op_lspi: // 0x4f (79)
1300 			// Same as the 4 ones above, except that the accumulator is used as
1301 			// an additional index
1302 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1303 			var_number = opparams[0] + (opcode >= op_lsgi ? s->r_acc.requireSint16() : 0);
1304 			PUSH32(read_var(s, var_type, var_number));
1305 			break;
1306 
1307 		case op_sag: // 0x50 (80)
1308 		case op_sal: // 0x51 (81)
1309 		case op_sat: // 0x52 (82)
1310 		case op_sap: // 0x53 (83)
1311 			// Save the accumulator into the global, local, temp or param variable
1312 		case op_sagi: // 0x58 (88)
1313 		case op_sali: // 0x59 (89)
1314 		case op_sati: // 0x5a (90)
1315 		case op_sapi: // 0x5b (91)
1316 			// Save the accumulator into the global, local, temp or param variable,
1317 			// using the accumulator as an additional index
1318 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1319 			var_number = opparams[0] + (opcode >= op_sagi ? s->r_acc.requireSint16() : 0);
1320 			if (opcode >= op_sagi)	// load the actual value to store in the accumulator
1321 				s->r_acc = POP32();
1322 			write_var(s, var_type, var_number, s->r_acc);
1323 			break;
1324 
1325 		case op_ssg: // 0x54 (84)
1326 		case op_ssl: // 0x55 (85)
1327 		case op_sst: // 0x56 (86)
1328 		case op_ssp: // 0x57 (87)
1329 			// Save the stack into the global, local, temp or param variable
1330 		case op_ssgi: // 0x5c (92)
1331 		case op_ssli: // 0x5d (93)
1332 		case op_ssti: // 0x5e (94)
1333 		case op_sspi: // 0x5f (95)
1334 			// Same as the 4 ones above, except that the accumulator is used as
1335 			// an additional index
1336 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1337 			var_number = opparams[0] + (opcode >= op_ssgi ? s->r_acc.requireSint16() : 0);
1338 			write_var(s, var_type, var_number, POP32());
1339 			break;
1340 
1341 		case op_plusag: // 0x60 (96)
1342 		case op_plusal: // 0x61 (97)
1343 		case op_plusat: // 0x62 (98)
1344 		case op_plusap: // 0x63 (99)
1345 			// Increment the global, local, temp or param variable and save it
1346 			// to the accumulator
1347 		case op_plusagi: // 0x68 (104)
1348 		case op_plusali: // 0x69 (105)
1349 		case op_plusati: // 0x6a (106)
1350 		case op_plusapi: // 0x6b (107)
1351 			// Same as the 4 ones above, except that the accumulator is used as
1352 			// an additional index
1353 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1354 			var_number = opparams[0] + (opcode >= op_plusagi ? s->r_acc.requireSint16() : 0);
1355 			s->r_acc = read_var(s, var_type, var_number) + 1;
1356 			write_var(s, var_type, var_number, s->r_acc);
1357 			break;
1358 
1359 		case op_plussg: // 0x64 (100)
1360 		case op_plussl: // 0x65 (101)
1361 		case op_plusst: // 0x66 (102)
1362 		case op_plussp: // 0x67 (103)
1363 			// Increment the global, local, temp or param variable and save it
1364 			// to the stack
1365 		case op_plussgi: // 0x6c (108)
1366 		case op_plussli: // 0x6d (109)
1367 		case op_plussti: // 0x6e (110)
1368 		case op_plusspi: // 0x6f (111)
1369 			// Same as the 4 ones above, except that the accumulator is used as
1370 			// an additional index
1371 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1372 			var_number = opparams[0] + (opcode >= op_plussgi ? s->r_acc.requireSint16() : 0);
1373 			r_temp = read_var(s, var_type, var_number) + 1;
1374 			PUSH32(r_temp);
1375 			write_var(s, var_type, var_number, r_temp);
1376 			break;
1377 
1378 		case op_minusag: // 0x70 (112)
1379 		case op_minusal: // 0x71 (113)
1380 		case op_minusat: // 0x72 (114)
1381 		case op_minusap: // 0x73 (115)
1382 			// Decrement the global, local, temp or param variable and save it
1383 			// to the accumulator
1384 		case op_minusagi: // 0x78 (120)
1385 		case op_minusali: // 0x79 (121)
1386 		case op_minusati: // 0x7a (122)
1387 		case op_minusapi: // 0x7b (123)
1388 			// Same as the 4 ones above, except that the accumulator is used as
1389 			// an additional index
1390 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1391 			var_number = opparams[0] + (opcode >= op_minusagi ? s->r_acc.requireSint16() : 0);
1392 			s->r_acc = read_var(s, var_type, var_number) - 1;
1393 			write_var(s, var_type, var_number, s->r_acc);
1394 			break;
1395 
1396 		case op_minussg: // 0x74 (116)
1397 		case op_minussl: // 0x75 (117)
1398 		case op_minusst: // 0x76 (118)
1399 		case op_minussp: // 0x77 (119)
1400 			// Decrement the global, local, temp or param variable and save it
1401 			// to the stack
1402 		case op_minussgi: // 0x7c (124)
1403 		case op_minussli: // 0x7d (125)
1404 		case op_minussti: // 0x7e (126)
1405 		case op_minusspi: // 0x7f (127)
1406 			// Same as the 4 ones above, except that the accumulator is used as
1407 			// an additional index
1408 			var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
1409 			var_number = opparams[0] + (opcode >= op_minussgi ? s->r_acc.requireSint16() : 0);
1410 			r_temp = read_var(s, var_type, var_number) - 1;
1411 			PUSH32(r_temp);
1412 			write_var(s, var_type, var_number, r_temp);
1413 			break;
1414 
1415 		default:
1416 			error("run_vm(): illegal opcode %x", opcode);
1417 
1418 		} // switch (opcode)
1419 
1420 		if (s->_executionStackPosChanged) // Force initialization
1421 			s->xs = xs_new;
1422 
1423 		if (s->xs != &(s->_executionStack.back())) {
1424 			error("xs is stale (%p vs %p); last command was %02x",
1425 					(void *)s->xs, (void *)&(s->_executionStack.back()),
1426 					opcode);
1427 		}
1428 		++s->scriptStepCounter;
1429 	}
1430 }
1431 
getPointer(SegManager * segMan) const1432 reg_t *ObjVarRef::getPointer(SegManager *segMan) const {
1433 	Object *o = segMan->getObject(obj);
1434 	return o ? &o->getVariableRef(varindex) : 0;
1435 }
1436 
getVarPointer(SegManager * segMan) const1437 reg_t *ExecStack::getVarPointer(SegManager *segMan) const {
1438 	assert(type == EXEC_STACK_TYPE_VARSELECTOR);
1439 	return addr.varp.getPointer(segMan);
1440 }
1441 
1442 } // End of namespace Sci
1443