Monday, June 15, 2009

Wine fun #2

Forgot to mention that the quick fix to solve the issue I was having, was to change the device mapping so that it doesn't have one pointing to the root of the filesystem anymore. On default wine makes a mapping for drive Z to the root of the filesystem, hence why it was able to find and open /dev/random. So the easy fix was to change the Z drive mapping in ~/.wine/dosdevices

Now I just have to find out why the game bombs out when pixel shaders are enabled...

Saturday, June 13, 2009

Wine fun

Don't ask me how I came to this situation, but I was trying to run a windows game on my home server over a VNC connection. Not exactly an ideal and speedy setup, but cool to see it's possible.

However, for some reason I could start the game with wine when I was at the console of the machine, but whenever I tried to start it over a VNC connection, it got stuck in the connection phase. It first looked like a network issue, but a wireshark trace didn't show anything. It was also hard to explain why it would work locally but not remote, first thought it was due to the network load of the VNC session or some timing issue. So it was time to have a closer look at it.

First up, strace of the process showed it was very slowly reading small amounts of bytes from a certain FD. A look into /proc/<pid>/fd/<num> showed it was trying to read from /dev/random. Now we're getting somewhere.

Interesting thing about /dev/random is that it needs a source for entropy. The available entropy can be viewed from /proc/sys/kernel/random/entropy_avail. Wrote a tiny bash script to continuously display that file, which clearly showed that once the connection stage of the game was reached, the pool drained at exactly the same time as the game froze.. and then whenever the pool refilled, it was quickly drained again. So the problem was, due to working remote on the machine, too little events were generated that contributed to the pool, which blocked the process reading from the random device.

Starting some heavy disk activity, showed that this was indeed the issue, because as soon as I did that, the game continued.

Next step was finding out why wine used /dev/random instead of /dev/urandom. However, a quick grep through the source didn't show any location where this would crop up in my situation. Weird.

Next idea was trying to see what the game was trying to open exactly. Luckily wine has some pretty nice debug infrastructure, so after playing with WINEDEBUG a bit. I found that the game was issuing a CreateFileA() with "/dev/random" as file name, which doesn't work on windows of course. A double check in the game executable shows that it does indeed just that:


.text:0042C150 sub_42C150 proc near
.text:0042C150
.text:0042C150 arg_0 = dword ptr 8
.text:0042C150 arg_4 = dword ptr 0Ch
.text:0042C150
.text:0042C150 push esi
.text:0042C151 push offset aRb ; "rb"
.text:0042C156 push offset aDevRandom ; "/dev/random"
.text:0042C15B call _fopen
.text:0042C160 mov esi, eax
.text:0042C162 add esp, 8
.text:0042C165 test esi, esi
.text:0042C167 jz short loc_42C185
.text:0042C169 push 0 ; size_t
.text:0042C16B push 4 ; int
.text:0042C16D push 0 ; char *
.text:0042C16F push esi ; FILE *
.text:0042C170 call _setvbuf
.text:0042C175 add esp, 10h
.text:0042C178 test eax, eax
.text:0042C17A jz short loc_42C189
.text:0042C17C push esi ; FILE *
.text:0042C17D call _fclose
.text:0042C182 add esp, 4
.text:0042C185
.text:0042C185 loc_42C185:
.text:0042C185 xor eax, eax
.text:0042C187 pop esi
.text:0042C188 retn
.text:0042C189 ; ---------------------------------------------------------------------------
.text:0042C189
.text:0042C189 loc_42C189:
.text:0042C189 mov eax, [esp+arg_4]
.text:0042C18D mov ecx, [esp+arg_0]
.text:0042C191 push edi
.text:0042C192 push esi ; int
.text:0042C193 push eax ; int
.text:0042C194 push 1 ; int
.text:0042C196 push ecx ; void *
.text:0042C197 call sub_436C04
.text:0042C19C push esi ; FILE *
.text:0042C19D mov edi, eax
.text:0042C19F call _fclose
.text:0042C1A4 add esp, 14h
.text:0042C1A7 mov eax, edi
.text:0042C1A9 pop edi
.text:0042C1AA pop esi
.text:0042C1AB retn
.text:0042C1AB sub_42C150 endp



It's still not clear why this is done in the game, might be a check for linux (although the game is only available on windows) or maybe it's some old left over code that they forgot to remove. Who knows.

Anyway seems that the fact that wine supports unix file names transparently has caused issues in other places too