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? 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
