[Vm-dev] Debugging Win64 Cog Spur
Nicolas Cellier
nicolas.cellier.aka.nice at gmail.com
Fri May 26 12:55:21 UTC 2017
2017-05-26 9:24 GMT+02:00 Nicolas Cellier <
nicolas.cellier.aka.nice at gmail.com>:
>
>
> 2017-05-25 17:49 GMT+02:00 Eliot Miranda <eliot.miranda at gmail.com>:
>
>> Hi Nicolas,
>>
>> On Wed, May 24, 2017 at 11:28 PM, Nicolas Cellier <
>> nicolas.cellier.aka.nice at gmail.com> wrote:
>>
>>> Great, you reproduced exact same behavior.
>>> The problem I have is effectively where to put the breakpoint.
>>> I think we can believe the output of (gdb) call printCallStack()
>>>
>>
>> here's one issue; the computation to see if the frame pointer is in use
>> fails. I'm executing this at the compilation break point for FilePath
>> class>pathName:isEncoded:
>>
>> (gdb) print /x CStackPointer
>> $7 = 0xef91d0
>> (gdb) print /x CFramePointer
>> $8 = 0x0
>> (gdb) print cFramePointerInUse
>> $9 = 0
>> (gdb) info registers
>> rax 0x68588f 6838415
>> rbx 0xffffffff 4294967295
>> rcx 0x68588f 6838415
>> rdx 0xabababab003a643a -6076574521274768326
>> rsi 0xfde9 65001
>> rdi 0x0 0
>> rbp 0xef5db0 0xef5db0
>> rsp 0xef5c50 0xef5c50
>> r8 0x0 0
>> r9 0xfffffffffbefbc48 -68174776
>> r10 0xe36e626d44726839 -2058599758222432199
>> r11 0x8101010101010100 -9151031864016699136
>> r12 0xffffffff 4294967295
>> r13 0x20 32
>> r14 0x7ffc202018f0 140720847460592
>> r15 0xf2faf0 15923952
>> rip 0x4015d9 0x4015d9 <warning+9>
>> eflags 0x206 [ PF IF ]
>> cs 0x33 51
>> ss 0x2b 43
>> ds 0x2b 43
>> es 0x2b 43
>> fs 0x53 83
>> gs 0x2b 43
>> (gdb)
>>
>>
>
> So ceCaptureStackPointers() must get the value of SP and eventually FP in
> the caller.
> For getting caller SP, it must unstack the push RBX, and the return
> address.
>
> But on Win64 ABI it's not enough, because stack space is reserved for the
> 4 register arguments even if there is less than 4...
> So we must add 32 bytes more to callee SP in order to retrieve caller SP...
>
>
Hmmm wrong guess from my side.
Some calls do explicitely reserve the stack space for saving the 4 register
parameters like:
0x518d06 <generateCaptureCStackPointers+150>: sub $0x20,%rsp
0x518d0a <generateCaptureCStackPointers+154>: callq 0x506220
<zeroOpcodeIndexForNewOpcodes>
0x518d0f <generateCaptureCStackPointers+159>: add $0x20,%rsp
but some do not:
0x4ed822 <generateStackPointerCapture+178>: mov
0x2071f7(%rip),%rdx # 0x6f4a20 <methodZoneBase>
0x4ed829 <generateStackPointerCapture+185>: mov %rdx,0x70(%rsp)
0x4ed82e <generateStackPointerCapture+190>: mov
0x207203(%rip),%rdx # 0x6f4a38 <trampolineTableIndex>
0x4ed835 <generateStackPointerCapture+197>: mov %rdx,0x68(%rsp)
0x4ed83a <generateStackPointerCapture+202>: callq 0x518c70
<generateCaptureCStackPointers>
0x4ed83f <generateStackPointerCapture+207>: callq
*0x2b199b(%rip) # 0x79f1e0 <ceCaptureCStackPointers>
0x4ed845 <generateStackPointerCapture+213>: callq 0x543650
<isCFramePointerInUse>
0x4ed84a <generateStackPointerCapture+218>: movslq %eax,%rcx
0x4ed84d <generateStackPointerCapture+221>: mov
%rcx,0x2b1844(%rip) # 0x79f098 <cFramePointerInUse>
If I put a breakpoint:
(gdb) break generateStackPointerCapture
then I see that the frame pointer is not in use in this function:
(gdb) print $rbp
$6 = (void *) 0x0
then:
(gdb) print $rsp
$7 = (void *) 0xf2f250
if I step over ceCaptureCStackPointers()
=> 0x4e00010: push %rbx
0x4e00011: mov $0x6dc018,%rbx
0x4e00018: mov %rbp,0xc3158(%rbx)
0x4e0001f: mov %rsp,%rax
0x4e00022: add $0x30,%rax
0x4e00026: mov %rax,0xc3140(%rbx)
0x4e0002d: pop %rbx
i find:
(gdb) print CFramePointer
$10 = (void *) 0x0
(gdb) print CStackPointer
$9 = (void *) 0xf2f270
0x20 too much...
The other sender of ceCaptureCStackPointers does not use sub $0x20,%rsp
either
0x428310 <enterSmalltalkExecutiveImplementation+144>: xor
%eax,%eax
0x428312 <enterSmalltalkExecutiveImplementation+146>: mov
%al,%dl
0x428314 <enterSmalltalkExecutiveImplementation+148>: mov
%dl,0x4d(%rsp)
0x428318 <enterSmalltalkExecutiveImplementation+152>: mov
0x4d(%rsp),%al
0x42831c <enterSmalltalkExecutiveImplementation+156>: mov
%al,0x4c(%rsp)
0x428320 <enterSmalltalkExecutiveImplementation+160>: callq
*0x376eba(%rip) # 0x79f1e0 <ceCaptureCStackPointers>
0x428326 <enterSmalltalkExecutiveImplementation+166>: lea
0x376c33(%rip),%rcx # 0x79ef60 <reenterInterpreter>
So I will have to revert last VMMaker change...
>
>>
>>> I've tried other means:
>>> - analyze direct usage of registers RCX & co from VMMaker
>>> if ever it could conflicts with WIN64 logical register assignment
>>> But I did not find anything
>>> - compile with MSVC 2017
>>> if ever the compiler could spit different warnings and give a clue
>>> alas it fails very early in readImageFromFileHeapSizeStartingAt
>>> (during checkAssumedCompactClasses)
>>> the failure is incomprehensible, because the debugger shows identical
>>> contents if I print:
>>>
>>> *((sqInt *)(classTableFirstPage+8+(51<<3)))
>>> 140697255509608 __int64
>>> *((sqInt *)(specialObjectsOop+8+(7<<3))) 140697255509608
>>> __int64
>>>
>>> nonetheless, the debugger enters into the if and execute
>>> invalidCompactClassError("Array");
>>>
>>> I'll have to debug it at assembler level, but it's driving me away from
>>> the original problem...
>>>
>>
>> Hmmm. I doubt this is a problem because the assert and debug VMs would
>> print a warning if this were wrong and they seem to be doing fine (I'm
>> using the clang build).
>>
>>
>>>
>>>
> This is a MSVC code generation bug.
>
>
>>
>>
>>
>> --
>> _,,,^..^,,,_
>> best, Eliot
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20170526/f34a47ec/attachment.html>
More information about the Vm-dev
mailing list