Disassembly of loop section that hangs the game for quite a while, maybe even forever.

OK, Let's suppose you are right :) How to fix this ? I tried setting ax to FFFF but then it seemed the program ended up outside of it's normal instructions, though I could be wrong.

How does your tool solve it ? I would assume setting AX or some pointer to 0/nil but perhaps FFFF is used as a nil indicator.

JCivED works with gamesave files (.SVE and .MAP), that do contain the "nextUnit" values.

For detection the source is available here: https://sourceforge.net/p/jcived/co...dd/civ/logic/validation/IntegrityChecker.java

It basically verifies integrity between a unit's "nextUnit" value, and the data of the designated "nextUnit": does "nextUnit" exist (=not destroyed=unit type not 0xFF) ? Is "nextUnit" really on same square (compare x and y) ? If more than 1 unit on a square, do they properly reference each other or one of them has "nextUnit" pointing to "null" (0xFF) ?

I realize the current code does not take into account your specific case: unit.nextUnit == unit... Maybe needs an update :)

The fixing itself is contained in another file (legacy code being slowly moved around): https://sourceforge.net/p/jcived/co...dev/src/dd/jcived/edition/GameSaveEditor.java

This code simply takes all detections output from the previous code, then recomputes the unit stacks pointers properly by checking square contents, units' positions and existence.

By collecting multiple save games right before this bug happens it might become possible to find the location in the computer program where this happens.

It would work by setting a watch on the next pointer and checking if the value becomes the same as the original/entity itself.

Then loading each save games, playing a couple of turns, and then hoping the watchpoint/databreakpoint condition gets triggered.

Data breakpoint:

Unit.Next = Unit

Or perhaps some more complex breakpoint, checking different locations, but mostly the same idea.

Then maybe an executable patch could be created to fix civ1.exe so that this never happens again ! =D That be great/awesome ! =D

Creating patches is among my hobbies :)

However, I suspect unit stack errors happen in many various cases.

In fact CIV.EXE contains several bugs, of varying occurences and amplitudes... So it may not be just one place to fix this...

As for detection, it seems especially tricky, because the stack data corruption may occur well before the acutal hanging, and since you can have up to 128 units per civ (8 civs max), that makes A LOT of places to monitor for "nextUnit" values.

Indirect efforts at the moment are more in the way of rebuilding a perfect clone, "including bugs" :), by meticulously reversing CIV.EXE. But it is a very long path...
 
I just encountered this loop bug again, hmm, this time I made a save state in dos-box, maybe now I can try and manipulate some registers or memory addresses/content, any suggestions ?

Another civilization 1 hang, disassembly:

LOOP1:

1E1E:000016B9 8B4608 mov ax,[bp+08] ss:[F006]=0600
1E1E:000016BC 3946E0 cmp [bp-20],ax ss:[EFDE]=0000
1E1E:000016BF 7503 jne 000016C4 ($+3) (down)
1E1E:000016C1 E98E00 jmp 00001752 ($+8e) (down)
1E1E:000016C4 B80006 mov ax,0600
1E1E:000016C7 F76E06 imul word [bp+06] ss:[F004]=B808
1E1E:000016CA 8BF0 mov si,ax
1E1E:000016CC B80C00 mov ax,000C
1E1E:000016CF F76EE0 imul word [bp-20] ss:[EFDE]=0000
1E1E:000016D2 03F0 add si,ax
1E1E:000016D4 F684D48108 test byte [si-7E2C],08 ds:[FFFFB1D4]=6E6
1E1E:000016D9 751D jne 000016F8 ($+1d) (down)
1E1E:000016DB B022 mov al,22
1E1E:000016DD F6ACD781 imul byte [si-7E29] ds:[FFFFB1D7]=2020
1E1E:000016E1 8BF8 mov di,ax
1E1E:000016E3 B80100 mov ax,0001
1E1E:000016E6 8A8D4811 mov cl,[di+1148] ds:[1148]=0000
1E1E:000016EA D3E0 shl ax,cl
1E1E:000016EC 0946E2 or [bp-1E],ax ss:[EFE0]=468B
1E1E:000016EF 83BD381100 cmp word [di+1138],0000 ds:[1138]=0000
1E1E:000016F6 EB37 jmp short 0000172F ($+37) (down)
1E1E:000016F8 837EFE05 cmp word [bp-02],0005 ss:[EFFC]=9A50
1E1E:000016FC 7534 jne 00001732 ($+34) (no jmp)
1E1E:000016FE B81C00 mov ax,001C
1E1E:00001701 F76EF4 imul word [bp-0C] ss:[EFF2]=FF50
1E1E:00001704 8BD8 mov bx,ax

LOOP2:

1E1E:0000172F FF46AC inc word [bp-54] ss:[EFAA]=6F13
1E1E:00001732 B80C00 mov ax,000C
1E1E:00001735 F76EE0 imul word [bp-20] ss:[EFDE]=0000
1E1E:00001738 8BD8 mov bx,ax
1E1E:0000173A B80006 mov ax,0600
1E1E:0000173D F76E06 imul word [bp+06] ss:[F004]=B808
1E1E:00001740 8BF0 mov si,ax
1E1E:00001742 8A80DE81 mov al,[bx+si-7E22] ds:[FFFFB4BA]=6863
1E1E:00001746 98 cbw
1E1E:00001747 8946E0 mov [bp-20],ax ss:[EFDE]=0000
1E1E:0000174A 3DFFFF cmp ax,FFFF
1E1E:0000174D 7403 je 00001752 ($+3) (no jmp)
1E1E:0000174F E967FF jmp 000016B9 ($-99) (up)
 
I think this might be a loop of 3 units or something, inspecting values at:

1E1E:00001747 8946E0 mov [bp-20],ax ss:[EFDE]=0000

AX values:
EAX=0000003D
EAX=00000000
EAX=0000003D
EAX=00000000

Seems like unit A pointing to unit B and unit B pointing to unit A.
 
I want to try and set some memory contents to some value, but I don't know how to do it in dos-box-x.

There is a command called: SM

According to HELP from DOS-BOS-X:

SM [seg]:[off] [val] [.]..- Set memory with following values.

I want to try and set

1E1E:00001747 8946E0 mov [bp-20],ax ss:[EFDE]=0000

ss:[EFDE]=0000 to something else ? maybe 0001 or something.
 
More up-to-date-information, I will copy it here:


"
It seems this guide is a bit out of date (not surprising after almost 12 years 😀). Is there a more recent guide somewhere?


EDIT: Just found the debugger topic in the developers section. Here's 0.74 help:


Debugger commands (enter all values in hex or as register):
--------------------------------------------------------------------------
F3/F6 - Previous command in history.
F4/F7 - Next command in history.
F5 - Run.
F9 - Set/Remove breakpoint.
F10/F11 - Step over / trace into instruction.
ALT + D/E/S/X/B - Set data view to DS:SI/ES:DI/SS:SP/DS:DX/ES:BX.
Escape - Clear input line.
Up/Down - Move code view cursor.
Page Up/Down - Scroll data view.
Home/End - Scroll log messages.
BP [segment]:[offset] - Set breakpoint.
BPINT [intNr] * - Set interrupt breakpoint.
BPINT [intNr] [ah] * - Set interrupt breakpoint with ah.
BPINT [intNr] [ah] [al] - Set interrupt breakpoint with ah and al.
BPM [segment]:[offset] - Set memory breakpoint (memory change).
BPPM [selector]:[offset]- Set pmode-memory breakpoint (memory change).
BPLM [linear address] - Set linear memory breakpoint (memory change).
BPLIST - List breakpoints.
BPDEL [bpNr] / * - Delete breakpoint nr / all.
C / D [segment]:[offset] - Set code / data view address.
DOS MCBS - Show Memory Control Block chain.
INT [nr] / INTT [nr] - Execute / Trace into interrupt.
LOG [num] - Write cpu log file.
LOGS/LOGL [num] - Write short/long cpu log file.
HEAVYLOG - Enable/Disable automatic cpu log when dosbox exits.
ZEROPROTECT - Enable/Disable zero code execution detection.
SR [reg] [value] - Set register value.
SM [seg]:[off] [val] [.]..- Set memory with following values.
IV [seg]:[off] [name] - Create var name for memory address.
SV [filename] - Save var list in file.
LV [filename] - Load var list from file.
ADDLOG [message] - Add message to the log file.
MEMDUMP [seg]:[off] [len] - Write memory to file memdump.txt.
"
 
I found a way to do it sort of:
D 0000:EFDE can set data view there or something
and
SM 0000:EFDE 0001 changed the memory contents.

Now trying to run it further.

No effect... trying to change AX when it compares somewhere... to 0000.
 
I MANAGED TO CORRECT IT AS FOLLOWS:

1E1E:0000174F E967FF jmp 000016B9 ($-99) (up)
1E1E:XXXXXXX

SET THE INSTRUCTION POINTER TO THE INSTRUCTION BELOW THAT ONE.

SO

SR EIP XXXXXXX

WHATEVER THE X IS.

ALSO LOAD STATE WORKED ! GREAT !
 
BIG SUCCCESS, I WENT TO WAR IMMEDIATELY AND SOMEHOW THAT CLEANED UP THE DEFECTIVE UNIT.

I GOT LUCKY AND THE RUSSIAN EMPIRE SPLIT IN TWO FACTIONS BECAUSE I TOOK HIS CAPITAL, MINSK, AND I DIDNT EVEN NOTICE IT WAS HIS CAPITAL HAHAHA.

SO NOW THE GAME IS SAVED YEAH, AND I CAN PLAY ON, THE SAME TECHNIQUE COULD BE USED TO FIX OTHER GAME HANGS COOL ! ;) =D
 
Last edited:
WHATEVER YOU DO, DON'T CLOSE THE DEBUGGER WINDOW, THIS SHUTS DOWN DOS-BOX, KINDA STUPID. NOT YET SURE HOW TO CLOSE IT.
 
I suspect this bug occurs when "activating" sentried units and then "re-sentrieing" them or fortifiying them.

At some point before the hang occurs in the youtube video I go to the city screen and then I un-sentry a couple of units, I believe it was in moskou perhaps... and then I decided to re-sentry and/or re-fortify them. I had a feeling this was going to cause a hang and it did. Could be a coincidence but still. I noticed same behaviour in the previous/original report possibly. I sentried a single ship or maybe two and this seemed to cause a hang as well. So un-sentry and sentry during same turn might be a bit dangerous to do in this game and has a small chance of causing an infinite loop ! ;)
 
WHATEVER YOU DO, DON'T CLOSE THE DEBUGGER WINDOW, THIS SHUTS DOWN DOS-BOX, KINDA STUPID. NOT YET SURE HOW TO CLOSE IT.
to resume execution just type RUN or hit F5 while in debugger. you don't need to close it.
 
Top Bottom