Changeset 219885 in webkit


Ignore:
Timestamp:
Jul 25, 2017 1:56:04 PM (7 years ago)
Author:
mark.lam@apple.com
Message:

Fix bugs in probe code to change sp on x86, x86_64 and 32-bit ARM.
https://bugs.webkit.org/show_bug.cgi?id=174809
<rdar://problem/33504759>

Reviewed by Filip Pizlo.

  1. When the probe handler function changes the sp register to point to the region of stack in the middle of the ProbeContext on the stack, there is a bug where the ProbeContext's register values to be restored can be over-written before they can be restored. This is now fixed.
  1. Added more robust probe tests for changing the sp register.
  1. Made existing probe tests to ensure that probe handlers were actually called.
  1. Added some verification to testProbePreservesGPRS().
  1. Change all the probe tests to fail early on discovering an error instead of batching till the end of the test. This helps point a finger to the failing issue earlier.

This patch was tested on x86, x86_64, and ARMv7. ARM64 probe code will be fixed
next in https://bugs.webkit.org/show_bug.cgi?id=174697.

  • assembler/MacroAssemblerARM.cpp:
  • assembler/MacroAssemblerARMv7.cpp:
  • assembler/MacroAssemblerX86Common.cpp:
  • assembler/testmasm.cpp:

(JSC::testProbeReadsArgumentRegisters):
(JSC::testProbeWritesArgumentRegisters):
(JSC::testProbePreservesGPRS):
(JSC::testProbeModifiesStackPointer):
(JSC::testProbeModifiesStackPointerToInsideProbeContextOnStack):
(JSC::testProbeModifiesStackPointerToNBytesBelowSP):
(JSC::testProbeModifiesProgramCounter):
(JSC::run):

Location:
trunk/Source/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r219874 r219885  
     12017-07-25  Mark Lam  <mark.lam@apple.com>
     2
     3        Fix bugs in probe code to change sp on x86, x86_64 and 32-bit ARM.
     4        https://bugs.webkit.org/show_bug.cgi?id=174809
     5        <rdar://problem/33504759>
     6
     7        Reviewed by Filip Pizlo.
     8
     9        1. When the probe handler function changes the sp register to point to the
     10           region of stack in the middle of the ProbeContext on the stack, there is a
     11           bug where the ProbeContext's register values to be restored can be over-written
     12           before they can be restored.  This is now fixed.
     13
     14        2. Added more robust probe tests for changing the sp register.
     15
     16        3. Made existing probe tests to ensure that probe handlers were actually called.
     17
     18        4. Added some verification to testProbePreservesGPRS().
     19
     20        5. Change all the probe tests to fail early on discovering an error instead of
     21           batching till the end of the test.  This helps point a finger to the failing
     22           issue earlier.
     23
     24        This patch was tested on x86, x86_64, and ARMv7.  ARM64 probe code will be fixed
     25        next in https://bugs.webkit.org/show_bug.cgi?id=174697.
     26
     27        * assembler/MacroAssemblerARM.cpp:
     28        * assembler/MacroAssemblerARMv7.cpp:
     29        * assembler/MacroAssemblerX86Common.cpp:
     30        * assembler/testmasm.cpp:
     31        (JSC::testProbeReadsArgumentRegisters):
     32        (JSC::testProbeWritesArgumentRegisters):
     33        (JSC::testProbePreservesGPRS):
     34        (JSC::testProbeModifiesStackPointer):
     35        (JSC::testProbeModifiesStackPointerToInsideProbeContextOnStack):
     36        (JSC::testProbeModifiesStackPointerToNBytesBelowSP):
     37        (JSC::testProbeModifiesProgramCounter):
     38        (JSC::run):
     39
    1402017-07-25  Brian Burg  <bburg@apple.com>
    241
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp

    r219740 r219885  
    216216    // MacroAssemblerARM::probe() has already generated code to store some values.
    217217    // The top of stack now looks like this:
    218     //     esp[0 * ptrSize]: probeFunction
    219     //     esp[1 * ptrSize]: arg
     218    //     esp[0 * ptrSize]: probe handler function
     219    //     esp[1 * ptrSize]: probe arg
    220220    //     esp[2 * ptrSize]: saved r3 / S0
    221221    //     esp[3 * ptrSize]: saved ip
     
    289289    //
    290290    // 2. Issue 1 means we will need to write to the stack location at
    291     //    ProbeContext.cpu.sp - 4. But if the user probe function had  modified
    292     //    the value of ProbeContext.cpu.sp to point in the range between
    293     //    &ProbeContext.cpu.ip thru &ProbeContext.cpu.aspr, then the action for
    294     //    Issue 1 may trash the values to be restored before we can restore
    295     //    them.
     291    //    ProbeContext.cpu.gprs[sp] - PTR_SIZE. But if the user probe function had
     292    //    modified the value of ProbeContext.cpu.gprs[sp] to point in the range between
     293    //    &ProbeContext.cpu.gprs[ip] thru &ProbeContext.cpu.sprs[aspr], then the action
     294    //    for Issue 1 may trash the values to be restored before we can restore them.
    296295    //
    297     //    The solution is to check if ProbeContext.cpu.sp contains a value in
     296    //    The solution is to check if ProbeContext.cpu.gprs[sp] contains a value in
    298297    //    the undesirable range. If so, we copy the remaining ProbeContext
    299     //    register data to a safe range (at memory lower than where
    300     //    ProbeContext.cpu.sp points) first, and restore the remaining register
    301     //    from this new range.
    302 
    303     "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "\n"
     298    //    register data to a safe area first, and restore the remaining register
     299    //    from this new safe area.
     300
     301    // The restore area for the pc will be located at 1 word below the resultant sp.
     302    // All restore values are located at offset <= PROBE_CPU_APSR_OFFSET. Hence,
     303    // we need to make sure that resultant sp > offset of apsr + 1.
     304    "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET + PTR_SIZE) "\n"
    304305    "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    305306    "cmp       lr, ip" "\n"
    306307    "bgt     " SYMBOL_STRING(ctiMasmProbeTrampolineEnd) "\n"
    307308
    308     // We get here because the new expected stack pointer location is lower
    309     // than where it's supposed to be. This means the safe range of stack
    310     // memory where we'll be copying the remaining register restore values to
    311     // might be in a region of memory below the sp i.e. unallocated stack
    312     // memory. This in turn makes it vulnerable to interrupts potentially
    313     // trashing the copied values. To prevent that, we must first allocate the
    314     // needed stack memory by adjusting the sp before the copying.
    315 
    316     "sub       lr, lr, #(6 * " STRINGIZE_VALUE_OF(PTR_SIZE)
    317     " + " STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) ")" "\n"
    318 
    319     "mov       ip, sp" "\n"
    320     "mov       sp, lr" "\n"
    321     "mov       lr, ip" "\n"
    322 
     309    // Getting here means that the restore area will overlap the ProbeContext data
     310    // that we will need to get the restoration values from. So, let's move that
     311    // data to a safe place before we start writing into the restore area.
     312    // Let's locate the "safe area" at 2x sizeof(ProbeContext) below where the
     313    // restore area. This ensures that:
     314    // 1. The safe area does not overlap the restore area.
     315    // 2. The safe area does not overlap the ProbeContext.
     316    //    This makes it so that we can use memcpy (does not require memmove) semantics
     317    //    to copy the restore values to the safe area.
     318   
     319    // lr already contains [sp, #STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET)].
     320    "sub       lr, lr, #(2 * " STRINGIZE_VALUE_OF(PROBE_ALIGNED_SIZE) ")" "\n"
     321
     322    "mov       ip, sp" "\n" // Save the original ProbeContext*.
     323
     324    // Make sure the stack pointer points to the safe area. This ensures that the
     325    // safe area is protected from interrupt handlers overwriting it.
     326    "mov       sp, lr" "\n" // sp now points to the new ProbeContext in the safe area.
     327
     328    "mov       lr, ip" "\n" // Use lr as the old ProbeContext*.
     329
     330    // Copy the restore data to the new ProbeContext*.
    323331    "ldr       ip, [lr, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
    324332    "str       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
     
    332340    "str       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n"
    333341
     342    // ctiMasmProbeTrampolineEnd expects lr to contain the sp value to be restored.
     343    // Since we used it as scratch above, let's restore it.
     344    "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
     345
    334346    SYMBOL_STRING(ctiMasmProbeTrampolineEnd) ":" "\n"
     347
     348    // Set up the restore area for sp and pc.
     349    // lr already contains [sp, #STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET)].
     350
     351    // Push the pc on to the restore area.
    335352    "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n"
    336     "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    337353    "sub       lr, lr, #" STRINGIZE_VALUE_OF(PTR_SIZE) "\n"
    338354    "str       ip, [lr]" "\n"
     355    // Point sp to the restore area.
    339356    "str       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    340357
     358    // All done with math i.e. won't trash the status register (apsr) and don't need
     359    // scratch registers (lr and ip) anymore. Restore apsr, lr, and ip.
    341360    "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n"
    342361    "msr       APSR, ip" "\n"
    343     "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n"
    344     "mov       lr, ip" "\n"
     362    "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n"
    345363    "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
     364
     365    // Restore the sp and pc.
    346366    "ldr       sp, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    347 
    348367    "pop       { pc }" "\n"
    349368);
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.cpp

    r219740 r219885  
    187187    // MacroAssemblerARMv7::probe() has already generated code to store some values.
    188188    // The top of stack now looks like this:
    189     //     esp[0 * ptrSize]: probeFunction
    190     //     esp[1 * ptrSize]: arg
     189    //     esp[0 * ptrSize]: probe handler function
     190    //     esp[1 * ptrSize]: probe arg
    191191    //     esp[2 * ptrSize]: saved r0
    192192    //     esp[3 * ptrSize]: saved ip
     
    255255    // 1. Normal ARM calling convention relies on moving lr to pc to return to
    256256    //    the caller. In our case, the address to return to is specified by
    257     //    ProbeContext.cpu.pc. And at that moment, we won't have any available
     257    //    ProbeContext.cpu.gprs[pc]. And at that moment, we won't have any available
    258258    //    scratch registers to hold the return address (lr needs to hold
    259     //    ProbeContext.cpu.lr, not the return address).
     259    //    ProbeContext.cpu.gprs[lr], not the return address).
    260260    //
    261261    //    The solution is to store the return address on the stack and load the
     
    263263    //
    264264    // 2. Issue 1 means we will need to write to the stack location at
    265     //    ProbeContext.cpu.sp - 4. But if the user probe function had modified
    266     //    the value of ProbeContext.cpu.sp to point in the range between
    267     //    &ProbeContext.cpu.ip thru &ProbeContext.cpu.aspr, then the action for
    268     //    Issue 1 may trash the values to be restored before we can restore
    269     //    them.
     265    //    ProbeContext.cpu.gprs[sp] - PTR_SIZE. But if the user probe function had
     266    //    modified the value of ProbeContext.cpu.gprs[sp] to point in the range between
     267    //    &ProbeContext.cpu.gprs[ip] thru &ProbeContext.cpu.sprs[aspr], then the action
     268    //    for Issue 1 may trash the values to be restored before we can restore them.
    270269    //
    271     //    The solution is to check if ProbeContext.cpu.sp contains a value in
     270    //    The solution is to check if ProbeContext.cpu.gprs[sp] contains a value in
    272271    //    the undesirable range. If so, we copy the remaining ProbeContext
    273     //    register data to a safe range (at memory lower than where
    274     //    ProbeContext.cpu.sp points) first, and restore the remaining register
    275     //    from this new range.
    276 
    277     "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "\n"
     272    //    register data to a safe area first, and restore the remaining register
     273    //    from this new safe area.
     274
     275    // The restore area for the pc will be located at 1 word below the resultant sp.
     276    // All restore values are located at offset <= PROBE_CPU_APSR_OFFSET. Hence,
     277    // we need to make sure that resultant sp > offset of apsr + 1.
     278    "add       ip, sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET + PTR_SIZE) "\n"
    278279    "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    279280    "cmp       lr, ip" "\n"
     
    281282    "bgt     " SYMBOL_STRING(ctiMasmProbeTrampolineEnd) "\n"
    282283
    283     // We get here because the new expected stack pointer location is lower
    284     // than where it's supposed to be. This means the safe range of stack
    285     // memory where we'll be copying the remaining register restore values to
    286     // might be in a region of memory below the sp i.e. unallocated stack
    287     // memory. This, in turn, makes it vulnerable to interrupts potentially
    288     // trashing the copied values. To prevent that, we must first allocate the
    289     // needed stack memory by adjusting the sp before the copying.
    290 
    291     "sub       lr, lr, #(6 * " STRINGIZE_VALUE_OF(PTR_SIZE)
    292     " + " STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) ")" "\n"
    293 
    294     "mov       ip, sp" "\n"
    295     "mov       sp, lr" "\n"
    296     "mov       lr, ip" "\n"
    297 
     284    // Getting here means that the restore area will overlap the ProbeContext data
     285    // that we will need to get the restoration values from. So, let's move that
     286    // data to a safe place before we start writing into the restore area.
     287    // Let's locate the "safe area" at 2x sizeof(ProbeContext) below where the
     288    // restore area. This ensures that:
     289    // 1. The safe area does not overlap the restore area.
     290    // 2. The safe area does not overlap the ProbeContext.
     291    //    This makes it so that we can use memcpy (does not require memmove) semantics
     292    //    to copy the restore values to the safe area.
     293
     294    // lr already contains [sp, #STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET)].
     295    "sub       lr, lr, #(2 * " STRINGIZE_VALUE_OF(PROBE_ALIGNED_SIZE) ")" "\n"
     296   
     297    "mov       ip, sp" "\n" // Save the original ProbeContext*.
     298   
     299    // Make sure the stack pointer points to the safe area. This ensures that the
     300    // safe area is protected from interrupt handlers overwriting it.
     301    "mov       sp, lr" "\n" // sp now points to the new ProbeContext in the safe area.
     302   
     303    "mov       lr, ip" "\n" // Use lr as the old ProbeContext*.
     304   
     305    // Copy the restore data to the new ProbeContext*.
    298306    "ldr       ip, [lr, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
    299307    "str       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
     
    307315    "str       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n"
    308316
     317    // ctiMasmProbeTrampolineEnd expects lr to contain the sp value to be restored.
     318    // Since we used it as scratch above, let's restore it.
     319    "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
     320
    309321    ".thumb_func " THUMB_FUNC_PARAM(ctiMasmProbeTrampolineEnd) "\n"
    310322    SYMBOL_STRING(ctiMasmProbeTrampolineEnd) ":" "\n"
     323
     324    // Set up the restore area for sp and pc.
     325    // lr already contains [sp, #STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET)].
     326
     327    // Push the pc on to the restore area.
    311328    "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_PC_OFFSET) "]" "\n"
    312     "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    313329    "sub       lr, lr, #" STRINGIZE_VALUE_OF(PTR_SIZE) "\n"
    314330    "str       ip, [lr]" "\n"
     331    // Point sp to the restore area.
    315332    "str       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    316333
     334    // All done with math i.e. won't trash the status register (apsr) and don't need
     335    // scratch registers (lr and ip) anymore. Restore apsr, lr, and ip.
    317336    "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_APSR_OFFSET) "]" "\n"
    318337    "msr       APSR, ip" "\n"
    319     "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n"
    320     "mov       lr, ip" "\n"
     338    "ldr       lr, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_LR_OFFSET) "]" "\n"
    321339    "ldr       ip, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_IP_OFFSET) "]" "\n"
     340
     341    // Restore the sp and pc.
    322342    "ldr       sp, [sp, #" STRINGIZE_VALUE_OF(PROBE_CPU_SP_OFFSET) "]" "\n"
    323 
    324343    "pop       { pc }" "\n"
    325344);
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.cpp

    r219740 r219885  
    172172    //     esp[0 * ptrSize]: eflags
    173173    //     esp[1 * ptrSize]: return address / saved eip
    174     //     esp[2 * ptrSize]: probeFunction
    175     //     esp[3 * ptrSize]: arg1
     174    //     esp[2 * ptrSize]: probe handler function
     175    //     esp[3 * ptrSize]: probe arg
    176176    //     esp[4 * ptrSize]: saved eax
    177177    //     esp[5 * ptrSize]: saved esp
     
    241241    // There are 6 more registers left to restore:
    242242    //     eax, ecx, ebp, esp, eip, and eflags.
    243     // We need to handle these last few restores carefully because:
    244     //
    245     // 1. We need to push the return address on the stack for ret to use.
    246     //    That means we need to write to the stack.
    247     // 2. The user probe function may have altered the restore value of esp to
    248     //    point to the vicinity of one of the restore values for the remaining
    249     //    registers left to be restored.
    250     //    That means, for requirement 1, we may end up writing over some of the
    251     //    restore values. We can check for this, and first copy the restore
    252     //    values to a "safe area" on the stack before commencing with the action
    253     //    for requirement 1.
    254     // 3. For requirement 2, we need to ensure that the "safe area" is
    255     //    protected from interrupt handlers overwriting it. Hence, the esp needs
    256     //    to be adjusted to include the "safe area" before we start copying the
    257     //    the restore values.
    258 
     243
     244    // The restoration process at ctiMasmProbeTrampolineEnd below works by popping
     245    // 5 words off the stack into eflags, eax, ecx, ebp, and eip. These 5 words need
     246    // to be pushed on top of the final esp value so that just by popping the 5 words,
     247    // we'll get the esp that the probe wants to set. Let's call this area (for storing
     248    // these 5 words) the restore area.
     249    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%ebp), %ecx" "\n"
     250    "subl $5 * " STRINGIZE_VALUE_OF(PTR_SIZE) ", %ecx" "\n"
     251
     252    // ecx now points to the restore area.
     253
     254    // Before we copy values from the ProbeContext to the restore area, we need to
     255    // make sure that the restore area does not overlap any of the values that we'll
     256    // be copying from in the ProbeContext. All the restore values to be copied from
     257    // comes from offset <= PROBE_CPU_EFLAGS_OFFSET in the ProbeContext.
    259258    "movl %ebp, %eax" "\n"
    260259    "addl $" STRINGIZE_VALUE_OF(PROBE_CPU_EFLAGS_OFFSET) ", %eax" "\n"
    261     "cmpl %eax, " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%ebp)" "\n"
     260    "cmpl %eax, %ecx" "\n"
    262261    "jg " SYMBOL_STRING(ctiMasmProbeTrampolineEnd) "\n"
    263262
    264     // Locate the "safe area" at 2x sizeof(ProbeContext) below where the new
    265     // rsp will be. This time we don't have to 32-byte align it because we're
    266     // not using this area to store any xmm regs.
    267     "movl " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%ebp), %eax" "\n"
     263    // Getting here means that the restore area will overlap the ProbeContext data
     264    // that we will need to get the restoration values from. So, let's move that
     265    // data to a safe place before we start writing into the restore area.
     266    // Let's locate the "safe area" at 2x sizeof(ProbeContext) below where the
     267    // restore area. This ensures that:
     268    // 1. The safe area does not overlap the restore area.
     269    // 2. The safe area does not overlap the ProbeContext.
     270    //    This makes it so that we can use memcpy (does not require memmove) semantics
     271    //    to copy the restore values to the safe area.
     272    // Note: the safe area does not have to 32-byte align it because we're not using
     273    // it to store any xmm regs.
     274    "movl %ecx, %eax" "\n"
    268275    "subl $2 * " STRINGIZE_VALUE_OF(PROBE_ALIGNED_SIZE) ", %eax" "\n"
     276
     277    // eax now points to the safe area.
     278
     279    // Make sure the stack pointer points to the safe area. This ensures that the
     280    // safe area is protected from interrupt handlers overwriting it.
    269281    "movl %eax, %esp" "\n"
    270282
    271     "subl $" STRINGIZE_VALUE_OF(PROBE_CPU_EAX_OFFSET) ", %eax" "\n"
    272283    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EAX_OFFSET) "(%ebp), %ecx" "\n"
    273284    "movl %ecx, " STRINGIZE_VALUE_OF(PROBE_CPU_EAX_OFFSET) "(%eax)" "\n"
     
    284295    "movl %eax, %ebp" "\n"
    285296
     297    // We used ecx above as scratch register. Let's restore it to points to the
     298    // restore area.
     299    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%ebp), %ecx" "\n"
     300    "subl $5 * " STRINGIZE_VALUE_OF(PTR_SIZE) ", %ecx" "\n"
     301
     302    // ecx now points to the restore area.
     303
    286304    SYMBOL_STRING(ctiMasmProbeTrampolineEnd) ":" "\n"
    287     "movl " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%ebp), %eax" "\n"
    288     "subl $5 * " STRINGIZE_VALUE_OF(PTR_SIZE) ", %eax" "\n"
    289     // At this point, %esp should be < %eax.
    290 
    291     "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EFLAGS_OFFSET) "(%ebp), %ecx" "\n"
    292     "movl %ecx, 0 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%eax)" "\n"
    293     "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EAX_OFFSET) "(%ebp), %ecx" "\n"
    294     "movl %ecx, 1 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%eax)" "\n"
    295     "movl " STRINGIZE_VALUE_OF(PROBE_CPU_ECX_OFFSET) "(%ebp), %ecx" "\n"
    296     "movl %ecx, 2 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%eax)" "\n"
    297     "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EBP_OFFSET) "(%ebp), %ecx" "\n"
    298     "movl %ecx, 3 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%eax)" "\n"
    299     "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EIP_OFFSET) "(%ebp), %ecx" "\n"
    300     "movl %ecx, 4 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%eax)" "\n"
    301     "movl %eax, %esp" "\n"
    302 
     305
     306    // Copy remaining restore values from the ProbeContext to the restore area.
     307    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EFLAGS_OFFSET) "(%ebp), %eax" "\n"
     308    "movl %eax, 0 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%ecx)" "\n"
     309    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EAX_OFFSET) "(%ebp), %eax" "\n"
     310    "movl %eax, 1 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%ecx)" "\n"
     311    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_ECX_OFFSET) "(%ebp), %eax" "\n"
     312    "movl %eax, 2 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%ecx)" "\n"
     313    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EBP_OFFSET) "(%ebp), %eax" "\n"
     314    "movl %eax, 3 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%ecx)" "\n"
     315    "movl " STRINGIZE_VALUE_OF(PROBE_CPU_EIP_OFFSET) "(%ebp), %eax" "\n"
     316    "movl %eax, 4 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%ecx)" "\n"
     317    "movl %ecx, %esp" "\n"
     318
     319    // Do the remaining restoration by popping off the restore area.
    303320    "popfd" "\n"
    304321    "popl %eax" "\n"
     
    322339    //     esp[0 * ptrSize]: rflags
    323340    //     esp[1 * ptrSize]: return address / saved rip
    324     //     esp[2 * ptrSize]: probeFunction
    325     //     esp[3 * ptrSize]: arg1
     341    //     esp[2 * ptrSize]: probe handler function
     342    //     esp[3 * ptrSize]: probe arg
    326343    //     esp[4 * ptrSize]: saved rax
    327344    //     esp[5 * ptrSize]: saved rsp
     
    421438    // There are 6 more registers left to restore:
    422439    //     rax, rcx, rbp, rsp, rip, and rflags.
    423     // We need to handle these last few restores carefully because:
    424     //
    425     // 1. We need to push the return address on the stack for ret to use
    426     //    That means we need to write to the stack.
    427     // 2. The user probe function may have altered the restore value of esp to
    428     //    point to the vicinity of one of the restore values for the remaining
    429     //    registers left to be restored.
    430     //    That means, for requirement 1, we may end up writing over some of the
    431     //    restore values. We can check for this, and first copy the restore
    432     //    values to a "safe area" on the stack before commencing with the action
    433     //    for requirement 1.
    434     // 3. For both requirement 2, we need to ensure that the "safe area" is
    435     //    protected from interrupt handlers overwriting it. Hence, the esp needs
    436     //    to be adjusted to include the "safe area" before we start copying the
    437     //    the restore values.
    438 
     440
     441    // The restoration process at ctiMasmProbeTrampolineEnd below works by popping
     442    // 5 words off the stack into rflags, rax, rcx, rbp, and rip. These 5 words need
     443    // to be pushed on top of the final esp value so that just by popping the 5 words,
     444    // we'll get the esp that the probe wants to set. Let's call this area (for storing
     445    // these 5 words) the restore area.
     446    "movq " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%rbp), %rcx" "\n"
     447    "subq $5 * " STRINGIZE_VALUE_OF(PTR_SIZE) ", %rcx" "\n"
     448
     449    // rcx now points to the restore area.
     450
     451    // Before we copy values from the ProbeContext to the restore area, we need to
     452    // make sure that the restore area does not overlap any of the values that we'll
     453    // be copying from in the ProbeContext. All the restore values to be copied from
     454    // comes from offset <= PROBE_CPU_EFLAGS_OFFSET in the ProbeContext.
    439455    "movq %rbp, %rax" "\n"
    440456    "addq $" STRINGIZE_VALUE_OF(PROBE_CPU_EFLAGS_OFFSET) ", %rax" "\n"
    441     "cmpq %rax, " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%rbp)" "\n"
     457    "cmpq %rax, %rcx" "\n"
    442458    "jg " SYMBOL_STRING(ctiMasmProbeTrampolineEnd) "\n"
    443459
    444     // Locate the "safe area" at 2x sizeof(ProbeContext) below where the new
    445     // rsp will be. This time we don't have to 32-byte align it because we're
    446     // not using to store any xmm regs.
    447     "movq " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%rbp), %rax" "\n"
     460    // Getting here means that the restore area will overlap the ProbeContext data
     461    // that we will need to get the restoration values from. So, let's move that
     462    // data to a safe place before we start writing into the restore area.
     463    // Let's locate the "safe area" at 2x sizeof(ProbeContext) below where the
     464    // restore area. This ensures that:
     465    // 1. The safe area does not overlap the restore area.
     466    // 2. The safe area does not overlap the ProbeContext.
     467    //    This makes it so that we can use memcpy (does not require memmove) semantics
     468    //    to copy the restore values to the safe area.
     469    // Note: the safe area does not have to 32-byte align it because we're not using
     470    // it to store any xmm regs.
     471    "movq %rcx, %rax" "\n"
    448472    "subq $2 * " STRINGIZE_VALUE_OF(PROBE_ALIGNED_SIZE) ", %rax" "\n"
     473
     474    // rax now points to the safe area.
     475
     476    // Make sure the stack pointer points to the safe area. This ensures that the
     477    // safe area is protected from interrupt handlers overwriting it.
    449478    "movq %rax, %rsp" "\n"
    450479
     
    463492    "movq %rax, %rbp" "\n"
    464493
     494    // We used rcx above as scratch register. Let's restore it to points to the
     495    // restore area.
     496    "movq " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%rbp), %rcx" "\n"
     497    "subq $5 * " STRINGIZE_VALUE_OF(PTR_SIZE) ", %rcx" "\n"
     498
     499    // rcx now points to the restore area.
     500
    465501    SYMBOL_STRING(ctiMasmProbeTrampolineEnd) ":" "\n"
    466     "movq " STRINGIZE_VALUE_OF(PROBE_CPU_ESP_OFFSET) "(%rbp), %rax" "\n"
    467     "subq $5 * " STRINGIZE_VALUE_OF(PTR_SIZE) ", %rax" "\n"
    468     // At this point, %rsp should be < %rax.
    469 
    470     "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EFLAGS_OFFSET) "(%rbp), %rcx" "\n"
    471     "movq %rcx, 0 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rax)" "\n"
    472     "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EAX_OFFSET) "(%rbp), %rcx" "\n"
    473     "movq %rcx, 1 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rax)" "\n"
    474     "movq " STRINGIZE_VALUE_OF(PROBE_CPU_ECX_OFFSET) "(%rbp), %rcx" "\n"
    475     "movq %rcx, 2 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rax)" "\n"
    476     "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EBP_OFFSET) "(%rbp), %rcx" "\n"
    477     "movq %rcx, 3 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rax)" "\n"
    478     "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EIP_OFFSET) "(%rbp), %rcx" "\n"
    479     "movq %rcx, 4 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rax)" "\n"
    480     "movq %rax, %rsp" "\n"
    481 
     502
     503    // Copy remaining restore values from the ProbeContext to the restore area.
     504    "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EFLAGS_OFFSET) "(%rbp), %rax" "\n"
     505    "movq %rax, 0 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rcx)" "\n"
     506    "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EAX_OFFSET) "(%rbp), %rax" "\n"
     507    "movq %rax, 1 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rcx)" "\n"
     508    "movq " STRINGIZE_VALUE_OF(PROBE_CPU_ECX_OFFSET) "(%rbp), %rax" "\n"
     509    "movq %rax, 2 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rcx)" "\n"
     510    "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EBP_OFFSET) "(%rbp), %rax" "\n"
     511    "movq %rax, 3 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rcx)" "\n"
     512    "movq " STRINGIZE_VALUE_OF(PROBE_CPU_EIP_OFFSET) "(%rbp), %rax" "\n"
     513    "movq %rax, 4 * " STRINGIZE_VALUE_OF(PTR_SIZE) "(%rcx)" "\n"
     514    "movq %rcx, %rsp" "\n"
     515
     516    // Do the remaining restoration by popping off the restore area.
    482517    "popfq" "\n"
    483518    "popq %rax" "\n"
  • trunk/Source/JavaScriptCore/assembler/testmasm.cpp

    r219821 r219885  
    3434#include <wtf/Compiler.h>
    3535#include <wtf/DataLog.h>
     36#include <wtf/Function.h>
    3637#include <wtf/Lock.h>
    3738#include <wtf/NumberOfCores.h>
     
    5657StaticLock crashLock;
    5758
    58 typedef std::function<void(CCallHelpers&)> Generator;
     59typedef WTF::Function<void(CCallHelpers&)> Generator;
    5960
    6061template<typename T> T nextID(T id) { return static_cast<T>(id + 1); }
     
    103104#endif // ENABLE(MASM_PROBE)
    104105
    105 MacroAssemblerCodeRef compile(Generator generate)
     106MacroAssemblerCodeRef compile(Generator&& generate)
    106107{
    107108    CCallHelpers jit;
     
    119120
    120121template<typename T, typename... Arguments>
    121 T compileAndRun(Generator generator, Arguments... arguments)
    122 {
    123     return invoke<T>(compile(generator), arguments...);
     122T compileAndRun(Generator&& generator, Arguments... arguments)
     123{
     124    return invoke<T>(compile(WTFMove(generator)), arguments...);
    124125}
    125126
     
    137138void testProbeReadsArgumentRegisters()
    138139{
    139     bool success = true;
     140    bool probeWasCalled = false;
    140141    compileAndRun<void>([&] (CCallHelpers& jit) {
    141142        jit.emitFunctionPrologue();
     
    158159
    159160        jit.probe([&] (ProbeContext* context) {
    160             success = success && context->gpr(GPRInfo::argumentGPR0) == testWord(0);
    161             success = success && context->gpr(GPRInfo::argumentGPR1) == testWord(1);
    162             success = success && context->gpr(GPRInfo::argumentGPR2) == testWord(2);
    163             success = success && context->gpr(GPRInfo::argumentGPR3) == testWord(3);
    164 
    165             success = success && context->fpr(FPRInfo::fpRegT0) == testWord32(0);
    166             success = success && context->fpr(FPRInfo::fpRegT1) == testWord32(1);
     161            probeWasCalled = true;
     162            CHECK(context->gpr(GPRInfo::argumentGPR0) == testWord(0));
     163            CHECK(context->gpr(GPRInfo::argumentGPR1) == testWord(1));
     164            CHECK(context->gpr(GPRInfo::argumentGPR2) == testWord(2));
     165            CHECK(context->gpr(GPRInfo::argumentGPR3) == testWord(3));
     166
     167            CHECK(context->fpr(FPRInfo::fpRegT0) == testWord32(0));
     168            CHECK(context->fpr(FPRInfo::fpRegT1) == testWord32(1));
    167169        });
    168170        jit.emitFunctionEpilogue();
    169171        jit.ret();
    170172    });
    171     CHECK(success);
     173    CHECK(probeWasCalled);
    172174}
    173175
     
    177179    // that we can read from argument registers. We'll use that ability to validate
    178180    // that our writes did take effect.
    179     bool success = true;
     181    unsigned probeCallCount = 0;
    180182    compileAndRun<void>([&] (CCallHelpers& jit) {
    181183        jit.emitFunctionPrologue();
     
    197199
    198200        // Write expected values.
    199         jit.probe([] (ProbeContext* context) {
     201        jit.probe([&] (ProbeContext* context) {
     202            probeCallCount++;
    200203            context->gpr(GPRInfo::argumentGPR0) = testWord(0);
    201204            context->gpr(GPRInfo::argumentGPR1) = testWord(1);
     
    209212        // Validate that expected values were written.
    210213        jit.probe([&] (ProbeContext* context) {
    211             success = success && context->gpr(GPRInfo::argumentGPR0) == testWord(0);
    212             success = success && context->gpr(GPRInfo::argumentGPR1) == testWord(1);
    213             success = success && context->gpr(GPRInfo::argumentGPR2) == testWord(2);
    214             success = success && context->gpr(GPRInfo::argumentGPR3) == testWord(3);
    215 
    216             success = success && context->fpr(FPRInfo::fpRegT0) == testWord32(0);
    217             success = success && context->fpr(FPRInfo::fpRegT1) == testWord32(1);
     214            probeCallCount++;
     215            CHECK(context->gpr(GPRInfo::argumentGPR0) == testWord(0));
     216            CHECK(context->gpr(GPRInfo::argumentGPR1) == testWord(1));
     217            CHECK(context->gpr(GPRInfo::argumentGPR2) == testWord(2));
     218            CHECK(context->gpr(GPRInfo::argumentGPR3) == testWord(3));
     219
     220            CHECK(context->fpr(FPRInfo::fpRegT0) == testWord32(0));
     221            CHECK(context->fpr(FPRInfo::fpRegT1) == testWord32(1));
    218222        });
    219223
     
    221225        jit.ret();
    222226    });
    223     CHECK(success);
     227    CHECK(probeCallCount == 2);
    224228}
    225229
     
    242246    // having already validated that we can read and write from registers. We'll use these abilities
    243247    // to validate that the probe preserves register values.
    244     bool success = true;
     248    unsigned probeCallCount = 0;
    245249    MacroAssembler::CPUState originalState;
    246250
     
    250254        // Write expected values into the registers (except for sp, fp, and pc).
    251255        jit.probe([&] (ProbeContext* context) {
     256            probeCallCount++;
    252257            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
    253258                originalState.gpr(id) = context->gpr(id);
     
    264269        // Invoke the probe to call a lot of functions and trash register values.
    265270        jit.probe([&] (ProbeContext*) {
    266             success = success && (testFunctionToTrashGPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
    267             success = success && (testFunctionToTrashFPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
     271            probeCallCount++;
     272            CHECK(testFunctionToTrashGPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
     273            CHECK(testFunctionToTrashFPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
    268274        });
    269275
    270276        // Validate that the registers have the expected values.
    271277        jit.probe([&] (ProbeContext* context) {
     278            probeCallCount++;
    272279            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
    273280                if (isPC(id))
    274281                    continue;
    275282                if (isSP(id) || isFP(id)) {
    276                     success = success && context->gpr(id) == originalState.gpr(id);
     283                    CHECK(context->gpr(id) == originalState.gpr(id));
    277284                    continue;
    278285                }
    279                 success = success && context->gpr(id) == testWord(id);
     286                CHECK(context->gpr(id) == testWord(id));
    280287            }
    281288            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
    282                 success = success && context->fpr(id) == testWord(id);
     289                CHECK(context->fpr(id) == testWord(id));
    283290        });
    284291
    285292        // Restore the original state.
    286293        jit.probe([&] (ProbeContext* context) {
     294            probeCallCount++;
    287295            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
    288296                if (isPC(id) || isSP(id) || isFP(id))
     
    292300            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
    293301                context->fpr(id) = originalState.fpr(id);
     302        });
     303
     304        // Validate that the original state was restored.
     305        jit.probe([&] (ProbeContext* context) {
     306            probeCallCount++;
     307            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     308                if (isPC(id) || isSP(id) || isFP(id))
     309                    continue;
     310                CHECK(context->gpr(id) == originalState.gpr(id));
     311            }
     312            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
     313                CHECK(context->fpr(id) == originalState.fpr(id));
    294314        });
    295315
     
    297317        jit.ret();
    298318    });
    299     CHECK(success);
    300 }
    301 
    302 void testProbeModifiesStackPointer()
    303 {
    304     bool success = true;
    305     uint8_t* originalSP;
     319    CHECK(probeCallCount == 5);
     320}
     321
     322void testProbeModifiesStackPointer(WTF::Function<void*(ProbeContext*)> computeModifiedStack)
     323{
     324    unsigned probeCallCount = 0;
     325    MacroAssembler::CPUState originalState;
     326    uint8_t* originalSP { nullptr };
     327    void* modifiedSP { nullptr };
     328#if CPU(X86) || CPU(X86_64) || CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
     329    uintptr_t modifiedFlags { 0 };
     330#endif
    306331
    307332    compileAndRun<void>([&] (CCallHelpers& jit) {
    308333        jit.emitFunctionPrologue();
    309334
    310         // Preserve original stack pointer and modify the sp.
    311         jit.probe([&] (ProbeContext* context) {
     335        // Preserve original stack pointer and modify the sp, and
     336        // write expected values into other registers (except for fp, and pc).
     337        jit.probe([&] (ProbeContext* context) {
     338            probeCallCount++;
     339            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     340                originalState.gpr(id) = context->gpr(id);
     341                if (isPC(id) || isSP(id) || isFP(id))
     342                    continue;
     343                context->gpr(id) = testWord(static_cast<int>(id));
     344            }
     345            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id)) {
     346                originalState.fpr(id) = context->fpr(id);
     347                context->fpr(id) = testWord(id);
     348            }
     349#if CPU(X86) || CPU(X86_64)
     350            originalState.spr(X86Registers::eflags) = context->spr(X86Registers::eflags);
     351            modifiedFlags = originalState.spr(X86Registers::eflags) ^ 0xc5;
     352            context->spr(X86Registers::eflags) = modifiedFlags;
     353#elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
     354            originalState.spr(ARMRegisters::apsr) = context->spr(ARMRegisters::apsr);
     355            modifiedFlags = originalState.spr(ARMRegisters::apsr) ^ 0xf0000000;
     356            context->spr(ARMRegisters::apsr) = modifiedFlags;
     357#endif
    312358            originalSP = reinterpret_cast<uint8_t*>(context->sp());
    313             context->sp() = originalSP - 1 * KB;
    314         });
    315 
    316         // Validate that the stack pointer has the expected value, and restore the original.
    317         jit.probe([&] (ProbeContext* context) {
    318             success = (reinterpret_cast<uint8_t*>(context->sp()) == (originalSP - 1 * KB));
     359            modifiedSP = computeModifiedStack(context);
     360            context->sp() = modifiedSP;
     361        });
     362
     363        // Validate that the registers have the expected values.
     364        jit.probe([&] (ProbeContext* context) {
     365            probeCallCount++;
     366            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     367                if (isPC(id) || isSP(id))
     368                    continue;
     369                if (isFP(id)) {
     370                    CHECK(context->gpr(id) == originalState.gpr(id));
     371                    continue;
     372                }
     373                CHECK(context->gpr(id) == testWord(id));
     374            }
     375            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
     376                CHECK(context->fpr(id) == testWord(id));
     377#if CPU(X86) || CPU(X86_64)
     378            CHECK(context->spr(X86Registers::eflags) == modifiedFlags);
     379#elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
     380            CHECK(context->spr(ARMRegisters::apsr) == modifiedFlags);
     381#endif
     382            CHECK(context->sp() == modifiedSP);
     383        });
     384
     385        // Restore the original state.
     386        jit.probe([&] (ProbeContext* context) {
     387            probeCallCount++;
     388            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     389                if (isPC(id) || isSP(id) || isFP(id))
     390                    continue;
     391                context->gpr(id) = originalState.gpr(id);
     392            }
     393            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
     394                context->fpr(id) = originalState.fpr(id);
     395#if CPU(X86) || CPU(X86_64)
     396            context->spr(X86Registers::eflags) = originalState.spr(X86Registers::eflags);
     397#elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
     398            context->spr(ARMRegisters::apsr) = originalState.spr(ARMRegisters::apsr);
     399#endif
    319400            context->sp() = originalSP;
    320401        });
    321402
    322         // Validate that the original stack pointer was restored.
    323         jit.probe([&] (ProbeContext* context) {
    324             success = (context->sp() == originalSP);
     403        // Validate that the original state was restored.
     404        jit.probe([&] (ProbeContext* context) {
     405            probeCallCount++;
     406            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     407                if (isPC(id) || isSP(id) || isFP(id))
     408                    continue;
     409                CHECK(context->gpr(id) == originalState.gpr(id));
     410            }
     411            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
     412                CHECK(context->fpr(id) == originalState.fpr(id));
     413#if CPU(X86) || CPU(X86_64)
     414            CHECK(context->spr(X86Registers::eflags) == originalState.spr(X86Registers::eflags));
     415#elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
     416            CHECK(context->spr(ARMRegisters::apsr) == originalState.spr(ARMRegisters::apsr));
     417#endif
     418            CHECK(context->sp() == originalSP);
    325419        });
    326420
     
    328422        jit.ret();
    329423    });
    330     CHECK(success);
     424    CHECK(probeCallCount == 4);
     425}
     426
     427void testProbeModifiesStackPointerToInsideProbeContextOnStack()
     428{
     429    for (size_t offset = 0; offset < sizeof(ProbeContext); offset += sizeof(uintptr_t)) {
     430        testProbeModifiesStackPointer([=] (ProbeContext* context) -> void* {
     431            return reinterpret_cast<uint8_t*>(context) + offset;
     432        });
     433    }
     434}
     435
     436void testProbeModifiesStackPointerToNBytesBelowSP()
     437{
     438    for (size_t offset = 0; offset < 1 * KB; offset += sizeof(uintptr_t)) {
     439        testProbeModifiesStackPointer([=] (ProbeContext* context) -> void* {
     440            return reinterpret_cast<uint8_t*>(context->cpu.sp()) - offset;
     441        });
     442    }
    331443}
    332444
     
    336448    // having already validated that we can read and write from registers. We'll use these abilities
    337449    // to validate that the probe preserves register values.
    338     bool success = false;
     450    unsigned probeCallCount = 0;
     451    bool continuationWasReached = false;
    339452
    340453    MacroAssemblerCodeRef continuation = compile([&] (CCallHelpers& jit) {
    341454        // Validate that we reached the continuation.
    342455        jit.probe([&] (ProbeContext*) {
    343             success = true;
     456            probeCallCount++;
     457            continuationWasReached = true;
    344458        });
    345459
     
    353467        // Write expected values into the registers.
    354468        jit.probe([&] (ProbeContext* context) {
     469            probeCallCount++;
    355470            context->pc() = continuation.code().executableAddress();
    356471        });
     
    358473        jit.breakpoint(); // We should never get here.
    359474    });
    360     CHECK(success);
     475    CHECK(probeCallCount == 2);
     476    CHECK(continuationWasReached);
    361477}
    362478#endif // ENABLE(MASM_PROBE)
     
    390506    RUN(testProbeWritesArgumentRegisters());
    391507    RUN(testProbePreservesGPRS());
    392     RUN(testProbeModifiesStackPointer());
     508    RUN(testProbeModifiesStackPointerToInsideProbeContextOnStack());
     509    RUN(testProbeModifiesStackPointerToNBytesBelowSP());
    393510    RUN(testProbeModifiesProgramCounter());
    394511#endif
Note: See TracChangeset for help on using the changeset viewer.