Argument unavailable and invalid pointer values

Hi,

we are running into a few issues when resolving local variables. The first issue is that sometimes an argument is marked as by LLDB, for example __$env in frame #2 of this backtrace:

  • thread #2: tid = 0xda984, 0x000000010026d464 ThreadTest`[J]com.robovm.debug.server.apps.SleeperThread.run(__$env=0x000000010285d280, __$this=0x000000010283a8e0)V + 72 at SleeperThread.java:12, stop reason = breakpoint 1.1
  • frame #0: 0x000000010026d464 ThreadTest[J]com.robovm.debug.server.apps.SleeperThread.run(__$env=0x000000010285d280, __$this=0x000000010283a8e0)V + 72 at SleeperThread.java:12 frame #1: 0x000000010030941e ThreadTest[j]java.lang.Runnable.run()V[Invokeinterface(java/lang/Thread)] + 9 at Thread.java:1
    frame #2: 0x0000000100307734 ThreadTest[J]java.lang.Thread.run(__$env=<unavailable>, __$this=0x0000000102817ab0)V + 76 at Thread.java:837 frame #3: 0x00000001005bb24e ThreadTest_call0 + 142 at call0-darwin-x86_64.s:80
    frame #4: 0x00000001005a181b ThreadTestcallVoidMethod(env=0x000000010285d280, callInfo=0x000000010528cc70) + 155 at method.c:620 frame #5: 0x00000001005a12da ThreadTestrvmCallVoidInstanceMethodA(env=0x000000010285d280, obj=0x0000000102817ab0, method=0x0000000102811320, args=0x000000010528cdd0) + 634 at method.c:759
    frame #6: 0x00000001005b9d67 ThreadTeststartThreadEntryPoint(_args=0x00007fff5fbff3e0) + 391 at thread.c:360 frame #7: 0x00000001005d0fc5 ThreadTestGC_inner_start_routine(sb=0x000000010528ceb8, arg=0x0000000102863ed0) + 117 at pthread_start.c:57
    frame #8: 0x00000001005cdeef ThreadTestGC_call_with_stack_base(fn=0x00000001005d0f50, arg=0x0000000102863ed0) + 63 at misc.c:1860 frame #9: 0x00000001005d243f ThreadTestGC_start_routine(arg=0x0000000102863ed0) + 31 at pthread_support.c:1666
    frame #10: 0x00007fff8f66f899 libsystem_pthread.dylib_pthread_body + 138 frame #11: 0x00007fff8f66f72a libsystem_pthread.dylib_pthread_start + 137
    frame #12: 0x00007fff8f673fc9 libsystem_pthread.dylib`thread_start + 13

This is a context struct that gets passed to all functions in this backtrace. While it’s not available for inspection in frame #2, it is available in in previous and subsequent frames (to which it gets passed by Thread.run). The argument is kept in rbx and passed to functions via rdi in the x86_64 assembler code. Any idea why it is marked as unavailable?

Related to this, we sometimes get very strange pointer values for arguments. E.g. we have a breakpoint in this function:

void _rvmHookThreadDetaching(Env* env, JavaThread* threadObj, Thread* thread, Object* throwable) {
fprintf(stderr, “[DEBUG] %s: Thread %lld detaching\n”, LOG_TAG, threadObj->id);
}

The breakpoint is a symbol breakpoint on _rvmHookThreadDetaching. Some times, threadObj has an invalid value, e.g. 0x3030303030313035, which is an invalid address, and almost seems like a sort of tomb stone value. The fun part is, that once we continue, the fprintf executes just fine, printing the value of threadObj->id, indicating that the inferior is actually using a valid address instead of the 0x3030303030313035 as reported by LLDB. We are also 100% certain that we never pass in an invalid address to this function (the caller goes on to use the threadObj value in subsequent statements, which would explode if the address was invalid).

We’d be happy for any pointers :slight_smile:

Thanks,
Mario

Hi,

we are running into a few issues when resolving local variables. The first issue is that sometimes an argument is marked as <unavailable> by LLDB, for example __$env in frame #2 of this backtrace:

* thread #2: tid = 0xda984, 0x000000010026d464 ThreadTest`[J]com.robovm.debug.server.apps.SleeperThread.run(__$env=0x000000010285d280, __$this=0x000000010283a8e0)V + 72 at SleeperThread.java:12, stop reason = breakpoint 1.1
  * frame #0: 0x000000010026d464 ThreadTest`[J]com.robovm.debug.server.apps.SleeperThread.run(__$env=0x000000010285d280, __$this=0x000000010283a8e0)V + 72 at SleeperThread.java:12
    frame #1: 0x000000010030941e ThreadTest`[j]java.lang.Runnable.run()V[Invokeinterface(java/lang/Thread)] + 9 at Thread.java:1
    frame #2: 0x0000000100307734 ThreadTest`[J]java.lang.Thread.run(__$env=<unavailable>, __$this=0x0000000102817ab0)V + 76 at Thread.java:837
    frame #3: 0x00000001005bb24e ThreadTest`_call0 + 142 at call0-darwin-x86_64.s:80
    frame #4: 0x00000001005a181b ThreadTest`callVoidMethod(env=0x000000010285d280, callInfo=0x000000010528cc70) + 155 at method.c:620
    frame #5: 0x00000001005a12da ThreadTest`rvmCallVoidInstanceMethodA(env=0x000000010285d280, obj=0x0000000102817ab0, method=0x0000000102811320, args=0x000000010528cdd0) + 634 at method.c:759
    frame #6: 0x00000001005b9d67 ThreadTest`startThreadEntryPoint(_args=0x00007fff5fbff3e0) + 391 at thread.c:360
    frame #7: 0x00000001005d0fc5 ThreadTest`GC_inner_start_routine(sb=0x000000010528ceb8, arg=0x0000000102863ed0) + 117 at pthread_start.c:57
    frame #8: 0x00000001005cdeef ThreadTest`GC_call_with_stack_base(fn=0x00000001005d0f50, arg=0x0000000102863ed0) + 63 at misc.c:1860
    frame #9: 0x00000001005d243f ThreadTest`GC_start_routine(arg=0x0000000102863ed0) + 31 at pthread_support.c:1666
    frame #10: 0x00007fff8f66f899 libsystem_pthread.dylib`_pthread_body + 138
    frame #11: 0x00007fff8f66f72a libsystem_pthread.dylib`_pthread_start + 137
    frame #12: 0x00007fff8f673fc9 libsystem_pthread.dylib`thread_start + 13

This is a context struct that gets passed to all functions in this backtrace. While it's not available for inspection in frame #2, it is available in in previous and subsequent frames (to which it gets passed by Thread.run). The argument is kept in rbx and passed to functions via rdi in the x86_64 assembler code. Any idea why it is marked as unavailable?

Because the compiler said it was unavailable in the DWARF debug info. DWARF has the ability to have a list of address ranges with locations for each range for a given variable:

Block [0x1000 - 0x2000)
    Variable "__$env" with variable value locations:
  [0x1000 - 0x1010) - rax
  [0x1020 - 0x1030) - deref(rsp + 10)

So if your function call is within the block [0x1000 - 0x2000) and the PC is not within [0x1000 - 0x1010) or [0x1020 - 0x1030), then the variable will be displayed as unavailable.

Related to this, we sometimes get very strange pointer values for arguments. E.g. we have a breakpoint in this function:

void _rvmHookThreadDetaching(Env* env, JavaThread* threadObj, Thread* thread, Object* throwable) {
    fprintf(stderr, "[DEBUG] %s: Thread %lld detaching\n", LOG_TAG, threadObj->id);
}

The breakpoint is a symbol breakpoint on _rvmHookThreadDetaching. Some times, threadObj has an invalid value, e.g. 0x3030303030313035, which is an invalid address, and almost seems like a sort of tomb stone value. The fun part is, that once we continue, the fprintf executes just fine, printing the value of threadObj->id, indicating that the inferior is actually using a valid address instead of the 0x3030303030313035 as reported by LLDB. We are also 100% certain that we never pass in an invalid address to this function (the caller goes on to use the threadObj value in subsequent statements, which would explode if the address was invalid).

This is again the compiler not giving you correct variable values in the DWARF. Many compilers will say that a variable is at "SP + offset" for a variable that is in the function, but that location isn't valid until the stack frame has been setup. So in some cases the compiler provides you with too generic of a location for a value. In this case the compiler just emits:

Block [0x1000 - 0x2000)
    Variable "__$env" with variable with a single location "SP + offset"

In this case, there is no location list for the variable, so it is assumed to be valid for the entire scope in which it exists [0x1000 - 0x2000)...

If you fix the compiler's DWARF debug info, it should fix things. LLDB is only as good as the info it is provided.

Greg

Hi,

i’ll check the DWARF for issue 1, sounds like that may be the cause.

However, for issue two i don’t think it can be the cause. This happens very sporadically when calling the function hundreds of times, during thr same prpcess run. Most of the time the address reported is valid, so the DWARF info must be correct. I guess we might have some other issue at hand and can rule out LLDB in this case.

Thanks!
Mario