DebugSession: no exception raised when stepping out of the execution?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

DebugSession: no exception raised when stepping out of the execution?

Thomas Dupriez-2
Hi,

I'm working with DebugSession to see if I can implement something that  
would step into an execution until a given expression evaluates to a  
different value than the value it had at the beginning to quickly  
localise the precise point where an invariant is broken.

But it appears that if the expression always evaluate to the same  
value, then the VM freezes.

I simplified my program to just stepInto a debugSession indefinitely,  
and it makes the VM freeze, while I would rather expect an exception  
to be raised (something like "ReachedEndOfExecution").

Here is my example code. Beware, running it will freeze the VM.

| program process context debugSession |
        program := [1+2].
        process := program newProcess.
        context := process suspendedContext.
        debugSession := process newDebugSessionNamed: 'StepIntoForever'  
startedAt: context.
        [ true ] whileTrue: [ debugSession stepInto ].

Is there a way to have an exception be raised when a stepInto message  
is sent to a debugSession whose execution is finished, instead of just  
freezing the VM?

Thomas


Reply | Threaded
Open this post in threaded view
|

Re: DebugSession: no exception raised when stepping out of the execution?

Ben Coman


On Mon, May 29, 2017 at 9:34 PM, <[hidden email]> wrote:
Hi,

I'm working with DebugSession to see if I can implement something that would step into an execution until a given expression evaluates to a different value than the value it had at the beginning to quickly localise the precise point where an invariant is broken.

But it appears that if the expression always evaluate to the same value, then the VM freezes.

I simplified my program to just stepInto a debugSession indefinitely, and it makes the VM freeze, while I would rather expect an exception to be raised (something like "ReachedEndOfExecution").

Here is my example code. Beware, running it will freeze the VM.

| program process context debugSession |
        program := [1+2].
        process := program newProcess.
        context := process suspendedContext.
        debugSession := process newDebugSessionNamed: 'StepIntoForever' startedAt: context.
        [ true ] whileTrue: [ debugSession stepInto ].

Is there a way to have an exception be raised when a stepInto message is sent to a debugSession whose execution is finished, instead of just freezing the VM?


I like looking into these sort of things, but right now don't have time. (I'm trying to be disciplined.)
Probably a way does not currently existing, so the way is to change the implementation.
What I'd suggest is debugging into #stepInto to maybe discover how to do it yourself.  :)  
As a novice I found it really accessible to dig into this stuff, found it quite enlightening and made me feel cool I could do it.
         
To be able to debug the debugger, first copy method #stepInto to #myStepInto with a halt at the top, then try...
    [ true ] whileTrue: [ debugSession myStepInto ].

btw, if you are executing your example from then Playground, note that it executes in the UI thread, which you've blocked from progressing.
Does the Image hang with this...? 
     [  [ true ] whileTrue: [ debugSession stepInto ] ] forkAt: Processor currentPriority - 1.

Note the lowered priority since processes are only pre-emptive between priorities. 
At the same priority processes are scheduled cooperatively, so require an explicit yield or the tight loop would dominate the UI process. 
So you might also try this...
     [  [ true ] whileTrue: [ debugSession stepInto. Processor yield. ] ] fork.

Give it a go and report back what you find and propose how you'd like it to work. 
Then we can see what it might break and wider implications I can't think of right now.
(Its a great learning experience for the experts to describe why some things are a bad idea, and maybe alternatives.)

cheers -ben

P.S. This might be the sort of thing that MetaLinks is good for, but I'm not much familiar with them.
Reply | Threaded
Open this post in threaded view
|

Re: DebugSession: no exception raised when stepping out of the execution?

Eliot Miranda-2
Hi Thomas,


On May 29, 2017, at 7:41 AM, Ben Coman <[hidden email]> wrote:



On Mon, May 29, 2017 at 9:34 PM, <[hidden email]> wrote:
Hi,

I'm working with DebugSession to see if I can implement something that would step into an execution until a given expression evaluates to a different value than the value it had at the beginning to quickly localise the precise point where an invariant is broken.

But it appears that if the expression always evaluate to the same value, then the VM freezes.

I simplified my program to just stepInto a debugSession indefinitely, and it makes the VM freeze, while I would rather expect an exception to be raised (something like "ReachedEndOfExecution").

Here is my example code. Beware, running it will freeze the VM.

| program process context debugSession |
        program := [1+2].
        process := program newProcess.
        context := process suspendedContext.
        debugSession := process newDebugSessionNamed: 'StepIntoForever' startedAt: context.
        [ true ] whileTrue: [ debugSession stepInto ].

Is there a way to have an exception be raised when a stepInto message is sent to a debugSession whose execution is finished, instead of just freezing the VM?


I like looking into these sort of things, but right now don't have time. (I'm trying to be disciplined.)
Probably a way does not currently existing, so the way is to change the implementation.
What I'd suggest is debugging into #stepInto to maybe discover how to do it yourself.  :)  

In particular, your use of stepInto: will soon step into the process termination code.  See newProcess.  You have to stop simulating before you stop the current process by mistake.

As a novice I found it really accessible to dig into this stuff, found it quite enlightening and made me feel cool I could do it.
         
To be able to debug the debugger, first copy method #stepInto to #myStepInto with a halt at the top, then try...
    [ true ] whileTrue: [ debugSession myStepInto ].

btw, if you are executing your example from then Playground, note that it executes in the UI thread, which you've blocked from progressing.
Does the Image hang with this...? 
     [  [ true ] whileTrue: [ debugSession stepInto ] ] forkAt: Processor currentPriority - 1.

Note the lowered priority since processes are only pre-emptive between priorities. 
At the same priority processes are scheduled cooperatively, so require an explicit yield or the tight loop would dominate the UI process. 
So you might also try this...
     [  [ true ] whileTrue: [ debugSession stepInto. Processor yield. ] ] fork.

Give it a go and report back what you find and propose how you'd like it to work. 
Then we can see what it might break and wider implications I can't think of right now.
(Its a great learning experience for the experts to describe why some things are a bad idea, and maybe alternatives.)

cheers -ben

P.S. This might be the sort of thing that MetaLinks is good for, but I'm not much familiar with them.
Reply | Threaded
Open this post in threaded view
|

Re: DebugSession: no exception raised when stepping out of the execution?

Guillermo Polito


On Mon, May 29, 2017 at 6:07 PM, Eliot Miranda <[hidden email]> wrote:
Hi Thomas,


On May 29, 2017, at 7:41 AM, Ben Coman <[hidden email]> wrote:



On Mon, May 29, 2017 at 9:34 PM, <[hidden email]> wrote:
[...] 

Here is my example code. Beware, running it will freeze the VM.

| program process context debugSession |
        program := [1+2].
        process := program newProcess.
        context := process suspendedContext.
        debugSession := process newDebugSessionNamed: 'StepIntoForever' startedAt: context.
        [ true ] whileTrue: [ debugSession stepInto ].

 [...]


In particular, your use of stepInto: will soon step into the process termination code.  See newProcess.  You have to stop simulating before you stop the current process by mistake.

 
Yes, I explained yesterday to Thomas that this would end up terminating the UIProcess where the debugger is running on, instead of terminating the process that is being debugged. But, it looks like a bug...

It would make sense to me that "Processor activeContext" yields the debugged context in the simulated code instead of the real active context. And I believe that this change should not break any existing code.

Actually, thinking a bit more about this, similar problems may happen if we try to execute in the debugger Semaphore code in the debugger. So probably, in general terms, the debugger should handle specially all code that messes up with the Process machinery.

--

   

Guille Polito


Research Engineer

French National Center for Scientific Research - http://www.cnrs.fr



Web: http://guillep.github.io

Phone: +33 06 52 70 66 13

Reply | Threaded
Open this post in threaded view
|

Re: DebugSession: no exception raised when stepping out of the execution?

Eliot Miranda-2
Hi Guille,

On Wed, May 31, 2017 at 12:48 AM, Guillermo Polito <[hidden email]> wrote:


On Mon, May 29, 2017 at 6:07 PM, Eliot Miranda <[hidden email]> wrote:
Hi Thomas,


On May 29, 2017, at 7:41 AM, Ben Coman <[hidden email]> wrote:



On Mon, May 29, 2017 at 9:34 PM, <[hidden email]> wrote:
[...] 

Here is my example code. Beware, running it will freeze the VM.

| program process context debugSession |
        program := [1+2].
        process := program newProcess.
        context := process suspendedContext.
        debugSession := process newDebugSessionNamed: 'StepIntoForever' startedAt: context.
        [ true ] whileTrue: [ debugSession stepInto ].

 [...]


In particular, your use of stepInto: will soon step into the process termination code.  See newProcess.  You have to stop simulating before you stop the current process by mistake.

 
Yes, I explained yesterday to Thomas that this would end up terminating the UIProcess where the debugger is running on, instead of terminating the process that is being debugged. But, it looks like a bug...

It would make sense to me that "Processor activeContext" yields the debugged context in the simulated code instead of the real active context. And I believe that this change should not break any existing code.

Actually, thinking a bit more about this, similar problems may happen if we try to execute in the debugger Semaphore code in the debugger. So probably, in general terms, the debugger should handle specially all code that messes up with the Process machinery.

Alas is isn't possible to implement this directly in the execution simulation machinery because of things like this:

Context>>runUntilErrorOrReturnFrom:
Context>>jump

Context>>jump uses the simulation machinery to advance execution, so the execution simulation machinery has to simulate exactly.   Context>>runUntilErrorOrReturnFrom: uses Context>>jump and is used in the exception delivery process.

I expect the process state changing primitives can apply to effectiveProcess.  So in Context>>doPrimitive:method:receiver:args:see

"Mutex>>primitiveEnterCriticalSection
Mutex>>primitiveTestAndSetOwnershipOfCriticalSection"
(primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue:
[| effective |
effective := Processor activeProcess effectiveProcess.
"active == effective"
value := primitiveIndex = 186
ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective]
ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective].
^(self isPrimFailToken: value)
ifTrue: [value]
ifFalse: [self push: value]].


We would have to have similar code for suspend and resume primitives.  I don't see how this mechanism solves the issues with wait and signal though.  They need to be handleable as per primitiveEnterCriticalSectionOnBehalfOf: etc.  We would have to modify the VM and add signalOnBehalfOf: and waitOnBehalfOf:.  There might be a bug tail here because I fear that the system depends on these being 0 argument primitives to avoid stack growth on signal/wait.

-- 

   

Guille Polito


Research Engineer

French National Center for Scientific Research - http://www.cnrs.fr



Web: http://guillep.github.io

Phone: <a href="tel:+33%206%2052%2070%2066%2013" value="+33652706613" target="_blank">+33 06 52 70 66 13




--
_,,,^..^,,,_
best, Eliot
Reply | Threaded
Open this post in threaded view
|

Re: DebugSession: no exception raised when stepping out of the execution?

Stephane Ducasse-3
Thanks eliot. I really think that pushing the debugger to the next level is an exciting perspective and I'm super happy that thomas accepted my crazy topics. 

Stef

On Fri, Jun 2, 2017 at 2:08 AM, Eliot Miranda <[hidden email]> wrote:
Hi Guille,

On Wed, May 31, 2017 at 12:48 AM, Guillermo Polito <[hidden email]> wrote:


On Mon, May 29, 2017 at 6:07 PM, Eliot Miranda <[hidden email]> wrote:
Hi Thomas,


On May 29, 2017, at 7:41 AM, Ben Coman <[hidden email]> wrote:



On Mon, May 29, 2017 at 9:34 PM, <[hidden email]> wrote:
[...] 

Here is my example code. Beware, running it will freeze the VM.

| program process context debugSession |
        program := [1+2].
        process := program newProcess.
        context := process suspendedContext.
        debugSession := process newDebugSessionNamed: 'StepIntoForever' startedAt: context.
        [ true ] whileTrue: [ debugSession stepInto ].

 [...]


In particular, your use of stepInto: will soon step into the process termination code.  See newProcess.  You have to stop simulating before you stop the current process by mistake.

 
Yes, I explained yesterday to Thomas that this would end up terminating the UIProcess where the debugger is running on, instead of terminating the process that is being debugged. But, it looks like a bug...

It would make sense to me that "Processor activeContext" yields the debugged context in the simulated code instead of the real active context. And I believe that this change should not break any existing code.

Actually, thinking a bit more about this, similar problems may happen if we try to execute in the debugger Semaphore code in the debugger. So probably, in general terms, the debugger should handle specially all code that messes up with the Process machinery.

Alas is isn't possible to implement this directly in the execution simulation machinery because of things like this:

Context>>runUntilErrorOrReturnFrom:
Context>>jump

Context>>jump uses the simulation machinery to advance execution, so the execution simulation machinery has to simulate exactly.   Context>>runUntilErrorOrReturnFrom: uses Context>>jump and is used in the exception delivery process.

I expect the process state changing primitives can apply to effectiveProcess.  So in Context>>doPrimitive:method:receiver:args:see

"Mutex>>primitiveEnterCriticalSection
Mutex>>primitiveTestAndSetOwnershipOfCriticalSection"
(primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue:
[| effective |
effective := Processor activeProcess effectiveProcess.
"active == effective"
value := primitiveIndex = 186
ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective]
ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective].
^(self isPrimFailToken: value)
ifTrue: [value]
ifFalse: [self push: value]].


We would have to have similar code for suspend and resume primitives.  I don't see how this mechanism solves the issues with wait and signal though.  They need to be handleable as per primitiveEnterCriticalSectionOnBehalfOf: etc.  We would have to modify the VM and add signalOnBehalfOf: and waitOnBehalfOf:.  There might be a bug tail here because I fear that the system depends on these being 0 argument primitives to avoid stack growth on signal/wait.

-- 

   

Guille Polito


Research Engineer

French National Center for Scientific Research - http://www.cnrs.fr



Web: http://guillep.github.io

Phone: <a href="tel:+33%206%2052%2070%2066%2013" value="+33652706613" target="_blank">+33 06 52 70 66 13




--
_,,,^..^,,,_
best, Eliot

Reply | Threaded
Open this post in threaded view
|

Re: DebugSession: no exception raised when stepping out of the execution?

Ben Coman
In reply to this post by Eliot Miranda-2


On Fri, Jun 2, 2017 at 8:08 AM, Eliot Miranda <[hidden email]> wrote:
Hi Guille,

On Wed, May 31, 2017 at 12:48 AM, Guillermo Polito <[hidden email]> wrote:


On Mon, May 29, 2017 at 6:07 PM, Eliot Miranda <[hidden email]> wrote:
Hi Thomas,


On May 29, 2017, at 7:41 AM, Ben Coman <[hidden email]> wrote:



On Mon, May 29, 2017 at 9:34 PM, <[hidden email]> wrote:
[...] 

Here is my example code. Beware, running it will freeze the VM.

| program process context debugSession |
        program := [1+2].
        process := program newProcess.
        context := process suspendedContext.
        debugSession := process newDebugSessionNamed: 'StepIntoForever' startedAt: context.
        [ true ] whileTrue: [ debugSession stepInto ].

 [...]


In particular, your use of stepInto: will soon step into the process termination code.  See newProcess.  You have to stop simulating before you stop the current process by mistake.

 
Yes, I explained yesterday to Thomas that this would end up terminating the UIProcess where the debugger is running on, instead of terminating the process that is being debugged. But, it looks like a bug...

It would make sense to me that "Processor activeContext" yields the debugged context in the simulated code instead of the real active context. And I believe that this change should not break any existing code.

Actually, thinking a bit more about this, similar problems may happen if we try to execute in the debugger Semaphore code in the debugger. So probably, in general terms, the debugger should handle specially all code that messes up with the Process machinery.

Alas is isn't possible to implement this directly in the execution simulation machinery because of things like this:

Context>>runUntilErrorOrReturnFrom:
Context>>jump

Context>>jump uses the simulation machinery to advance execution, so the execution simulation machinery has to simulate exactly.   Context>>runUntilErrorOrReturnFrom: uses Context>>jump and is used in the exception delivery process.

I expect the process state changing primitives can apply to effectiveProcess.  So in Context>>doPrimitive:method:receiver:args:see

"Mutex>>primitiveEnterCriticalSection
Mutex>>primitiveTestAndSetOwnershipOfCriticalSection"
(primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue:
[| effective |
effective := Processor activeProcess effectiveProcess.
"active == effective"
value := primitiveIndex = 186
ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective]
ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective].
^(self isPrimFailToken: value)
ifTrue: [value]
ifFalse: [self push: value]].


We would have to have similar code for suspend and resume primitives.  I don't see how this mechanism solves the issues with wait and signal though.  They need to be handleable as per primitiveEnterCriticalSectionOnBehalfOf: etc.  We would have to modify the VM and add signalOnBehalfOf: and waitOnBehalfOf:.  There might be a bug tail here because I fear that the system depends on these being 0 argument primitives to avoid stack growth on signal/wait.

This is what I touching on here.. 

cheers -ben