On Jun 11, 2013, at 11:38 AM, Andrey Zaytsev <[email protected]> 
wrote:

> Hello, Jim
> 
> The code I was debugging in described case is GCD-related stuff so the issue 
> with locks could be the cause. But issue is gone once we select thread/frame 
> - that's weird.
> 
> On Jun 11, 2013, at 3:38 AM, [email protected] wrote:
> 
>> One of the big dangers with evaluating expressions that run code in the 
>> debugee is that the code you run might try to acquire some locked resource 
>> that is held by another thread in the program.  That will cause the 
>> expression evaluation to deadlock.  
>> 
>> One solution is to run the expression evaluation with a timeout, and if it 
>> takes too long, cancel the expression, clean up its stack and return an 
>> error.  However, that can also be dangerous, for instance if the expression 
>> you run successfully acquires lock A, tries to get lock B, but that is held 
>> on another thread, so it deadlocks.  If you cancel the expression evaluation 
>> at that point, you will leave lock A stranded, and your program going to 
>> grind to a halt as different threads all try to get that resource.
>> 
>> The obvious solution to this problem is to run all threads when you do, 
>> expression evaluation.  However, that's not what most users want, they would 
>> find it disconcerting to have expression evaluation on one thread to cause 
>> some other thread to make progress.
>> 
>> lldb's solution to this problem is that when we run expressions, we first 
>> try running just the thread on which the expression is evaluated, but with 
>> some timeout (which is user settable.)  If the expression evaluation times 
>> out on the one thread, and the "run_others" parameter to RunThreadPlan is 
>> passed in as true, we will interrupt the evaluation, and then restart with 
>> all threads running.  So it is very possible that expression evaluation 
>> could cause another thread to get a chance to execute, which could in turn 
>> hit a breakpoint, or crash, or whatever else a thread might do while 
>> executing...
>> 
>> Short of the ability to track all locks in the system (a capability which 
>> most OS'es don't provide), this is the safest way around this problem.  It 
>> will fail if the expression you are running tries to acquire a non-recursive 
>> lock held on the thread which runs the code.  We could work around even that 
>> if we made up a debugger thread in the debugee for running expressions, 
>> though that would fail if any of the code in the expression tried to access 
>> thread specific data.  I don't know whether it is possible to fake a 
>> thread's thread specific data so it looks like it belongs to another thread. 
>>  If that's possible, we could probably make that work.  OTOH, this 
>> particular problem doesn't seem to occur that often.
>> 
>> Anyway, again without being able to play around with the locks in a program 
>> directly, I can't see a way to run general expressions that might acquire 
>> locked resources without allowing all threads to run, at least as a fallback.
> 
> What does it mean for debugger's front-end? What shall we see after 
> evaluation? Threads will stop in different frames and do we need to refetch 
> all info about all threads/frames/variables to display correct data?

Yes, if other threads get a chance to run, you will need to refresh state.  
There isn't any notification that this has happened at present.  I think it 
would be hard for us to know that other threads actually got a chance to run, 
all we can tell is that it could have happened.  But still, it might be a good 
idea to return that fact from the expression evaluation somehow...

Jim

> 
> Thank you Jim, for such a detailed clarification about LLDB internals. I'll 
> try to investigate the issue deeper and write back if I have some questions.
> 
>> 
>> Jim
>> 
>> On Jun 10, 2013, at 4:18 PM, Andrey Zaytsev <[email protected]> 
>> wrote:
>> 
>>> Hi Jim,
>>> 
>>> You're right that it uses correct context of frame specified. But as far as 
>>> I can see, real execution is running in other thread. May it cause 
>>> something like EXC_ARM_BREAKPOINT?
>>> And what run_others parameter of Process::RunThreadPlan() does?
>>> 
>>> 
>>> On Jun 11, 2013, at 2:07 AM, [email protected] wrote:
>>> 
>>>> That is not the intention of the design, and also not what I see:
>>>> 
>>>> (lldb) source list -f foo.c -l 1
>>>>  1         #include <stdio.h>
>>>>  2         
>>>>  3         int
>>>>  4         foo (int input)
>>>>  5         {
>>>>  6           int local_var = input * 5;
>>>>  7           printf ("Local var: %d.\n", local_var);
>>>>  8           return local_var;
>>>>  9         }
>>>>  10        
>>>>  11        int
>>>> (lldb) 
>>>>  12        main (int argc, char **argv)
>>>>  13        {
>>>>  14          int local_var = argc;
>>>>  15          printf ("Foo returns: %d.\n", foo (local_var));
>>>>  16          return 1;
>>>>  17        }
>>>> (lldb) b s -p "return local_var"
>>>> Breakpoint 1: where = foo`foo + 41 at foo.c:8, address = 0x0000000100000ef9
>>>> (lldb) run
>>>> Process 98518 launched: '/private/tmp/foo' (x86_64)
>>>> Local var: 5.
>>>> Process 98518 stopped
>>>> * thread #1: tid = 0x3663ec, function: foo , stop reason = breakpoint 1.1
>>>>   frame #0: 0x0000000100000ef9 foo`foo at foo.c:8
>>>>  5         {
>>>>  6           int local_var = input * 5;
>>>>  7           printf ("Local var: %d.\n", local_var);
>>>> -> 8         return local_var;
>>>>  9         }
>>>>  10        
>>>>  11        int
>>>> 
>>>> So I am in foo, there is a "local_var" in frame 0, where its value is 5, 
>>>> and in frame 1 where its value is 1.  So I do:
>>>> 
>>>> (lldb) script
>>>> Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>>>>>> frame_0 = lldb.thread.GetFrameAtIndex(0)
>>>>>>> print frame_0.EvaluateExpression("local_var")
>>>> (int) $0 = 5
>>>>>>> frame_1 = lldb.thread.GetFrameAtIndex(1)
>>>>>>> print frame_1.EvaluateExpression("local_var")
>>>> (int) $1 = 1
>>>>>>> quit()
>>>> 
>>>> SBFrame::EvaluateExpression, at least in this example, works on the 
>>>> SBFrame that you call it on.
>>>> 
>>>> Note, here I am using lldb.thread, which is INDEED the command 
>>>> interpreter's currently selected thread.  I just did that to shorten the 
>>>> example.  If you wanted to get the process/thread/frame independent of 
>>>> entities selected in the Command Interpreter, then you should use the 
>>>> accessors on SBDebugger, SBTarget, SBProcess and SBThread.  The Python 
>>>> docs explicitly state that you should NOT use lldb.process/lldb.thread or 
>>>> lldb.frame anywhere but in the interactive script interpreter.  They 
>>>> aren't even guaranteed to be set in other contexts.
>>>> 
>>>> Anyway, if you have some example (not using 
>>>> lldb.process/lldb.thread/lldb.frame) where the EvaluateExpression on a 
>>>> SBFrame object is evaluating the expression is the context of some other 
>>>> frame, please file a bug and we will take a look.
>>>> 
>>>> Jim
>>>> 
>>>> 
>>>> On Jun 10, 2013, at 1:46 PM, Andrey Zaytsev <[email protected]> 
>>>> wrote:
>>>> 
>>>>> Hello everyone.
>>>>> 
>>>>> I just realised thing which leads to crash of debuggee in some cases. We 
>>>>> had a bug in our tracker: http://youtrack.jetbrains.com/issue/OC-7389
>>>>> 
>>>>> We have some system of value renderers. Each renderer(e.g for 
>>>>> NSCollections) evaluates some stuff to get info about collection 
>>>>> elements. So does a number of Summary and Synthetic Providers too.
>>>>> 
>>>>> In SB-API it is implemented with EvaluateExpression function. One of the 
>>>>> ways we can evaluate expression is to call 
>>>>> lldb::SBFrame::EvaluateExpression() member function. Actually it performs 
>>>>> execution on selected thread/frame. But not on the frame we call 
>>>>> EvaluateExpression function on. It's very not obvious and in my opinion 
>>>>> buggy. Usage of API in this way leads to crashes of debuggee process like 
>>>>> in the ticket above. So crashes not only attempt to evaluate expression 
>>>>> but attempt to get local variables with dynamic types if it executes 
>>>>> target as well.
>>>>> 
>>>>> So workaround for us was to select specified thread/frame before doing 
>>>>> evaluation. So does interpreter's expr command.
>>>>> 
>>>>> 
>>>>> -- 
>>>>> Andrey Zaytsev
>>>>> Software Developer
>>>>> JetBrains, Inc
>>>>> http://www.jetbrains.com/
>>>>> "Develop with pleasure!"
>>>>> 
>>>>> _______________________________________________
>>>>> lldb-dev mailing list
>>>>> [email protected]
>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to