The size of the breakpoint instruction is set by 
GetSoftwareBreakpointTrapOpcode().  In your case, most likely you're in 
PlatformDarwin::GetSoftwareBreakpointTrapOpcode() - lldb uses the symbol table 
(from the binary file) to determine if the code in a given function is arm or 
thumb.  If it's arm, a 4 byte breakpoint is used.  If it's thumb, a 2 byte 
breakpoint.  Of course thumbv2 of T32 instructions can be 4 bytes -- the blne 
instruction is in your program -- but I assume the 2 byte breakpoint 
instruction still works correctly in these cases; the cpu sees the 2-byte 
instruction and stops execution.

I am a little wary about the fact that this comes after an it instruction, I 
kind of vaguely remember issues with that instruction's behavior.  

It shouldn't make any difference but you might want to try

(lldb) settings set target.use-fast-stepping false

which will force lldb to single instruction step through the function.  Right 
now lldb is looking at the instruction stream and putting breakpoints on 
branch/call/jump instructions to do your high-level "step" command, instead of 
stopping on every instruction.  It is possible there could be a problem with 
that approach and the it instruction.  Please report back if this changes the 
behavior.

J


> On Nov 26, 2014, at 9:22 AM, Mario Zechner <badlogicga...@gmail.com> wrote:
> 
> I dug a little deeper, inspecting the GDB remote packets send by LLDB to 
> perform the stepping. It appears when sending memory breakpoint commands used 
> for stepping, the size of the instruction being replaced isn't taken into 
> account, or writing back the original instruction isn't done properly. The 
> following log shows what happens when stepping into the previously mentioned 
> function:
> 
> (lldb) s
> Process 166 stopped
> * thread #1: tid = 0x0fd9, 0x002602e0 
> AttachTestIOSDev`[J]java.lang.Object.<init>(__$env=0x016bffc8, 
> __$this=0x017864b0)V + 12 at Object.java:136, queue = 
> 'com.apple.main-thread', stop reason = step in
>     frame #0: 0x002602e0 
> AttachTestIOSDev`[J]java.lang.Object.<init>(__$env=0x016bffc8, 
> __$this=0x017864b0)V + 12 at Object.java:136
> (lldb) disassemble -p
> AttachTestIOSDev`[J]java.lang.Object.<init>()V + 12 at Object.java:136:
> -> 0x2602e0:  ldr    r2, [r1]
>    0x2602e2:  ldr    r2, [r2, #0x30]
>    0x2602e4:  tst.w  r2, #0x100000
>    0x2602e8:  it     ne
> (lldb) s
> Process 166 stopped
> * thread #1: tid = 0x0fd9, 0x002602ec 
> AttachTestIOSDev`[J]java.lang.Object.<init>(__$env=0x016bffc8, 
> __$this=0x017864b0)V + 24 at Object.java:136, queue = 
> 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION 
> (code=EXC_ARM_UNDEFINED, subcode=0xffd1b001)
>     frame #0: 0x002602ec 
> AttachTestIOSDev`[J]java.lang.Object.<init>(__$env=0x016bffc8, 
> __$this=0x017864b0)V + 24 at Object.java:136
> (lldb) disassemble -p
> AttachTestIOSDev`[J]java.lang.Object.<init>()V + 24 at Object.java:136:
> -> 0x2602ec:  .long  0xb001ffd1                ; unknown opcode
>    0x2602f0:  pop    {r7, pc}
> 
> AttachTestIOSDev`[J]java.lang.Object.<init>()V + 30:
>    0x2602f2:  nop    
> 
> AttachTestIOSDev`[J]java.lang.Object.clone()Ljava/lang/Object; at 
> Object.java:154:
>    0x2602f4:  push   {r4, r5, r7, lr}
> (lldb) disassemble -f
> AttachTestIOSDev`[J]java.lang.Object.<init>()V at Object.java:136:
>    0x2602d4:  push   {r7, lr}
>    0x2602d6:  mov    r7, sp
>    0x2602d8:  sub    sp, #0x4
>    0x2602da:  movs   r2, #0x0
>    0x2602dc:  str    r2, [sp]
>    0x2602de:  str    r1, [sp]
>    0x2602e0:  ldr    r2, [r1]
>    0x2602e2:  ldr    r2, [r2, #0x30]
>    0x2602e4:  tst.w  r2, #0x100000
>    0x2602e8:  it     ne
>    0x2602ea:  blne   0x44b290                  ; _bcRegisterFinalizer
>    0x2602ee:  add    sp, #0x4
>    0x2602f0:  pop    {r7, pc}
> 
> AttachTestIOSDev`[J]java.lang.Object.<init>()V + 30:
>    0x2602f2:  nop    
> 
> The first step succeeds and ends up right after the prologue, at 0x2602e0:  
> ldr    r2, [r1]. The next step ends up at 0x2602ec:  .long  0xb001ffd1 which 
> is wrong, it should be 0x2602ea:  blne   0x44b290.
> 
> The GDB remote conversation between lldb and the debugserver on the device 
> (only relevant parts):
> 
> # First step
> lldb->debugserver: $Z0,2602e0,2#73
> debugserver->lldb: $OK#00
> lldb->debugserver: $vCont;c:0fd9#15
> debugserver->lldb: (320) 
> $T05thread:fd9;qaddr:37ebfad0;threads:fd9,ffa,ffb,ffd,fff,1009,100a,100b;00:c8ff6b01;01:b0647801;02:00000000;03:c87d6a00;04:00000000;05:c8ff6b01;06:fc6a6501;07:0c6a6501;08:90e96b01;09:28000000;0a:74a0ea37;0b:c8ff6b01;0c:b09e5b00;0d:086a6501;0e:d1b22000;0f:
> 
> # Second step
> lldb->debugserver: $Z0,2602ea,2#a4
> debugserver->lldb: $OK#00
> lldb->debugserver: $vCont;c:0fd9#15
> debugserver->lldb: (324) 
> $T92thread:fd9;qaddr:37ebfad0;threads:fd9,ffa,ffb,ffd,fff,1009,100a,100b;00:c8ff6b01;01:b0647801;02:01004300;03:c87d6a00;04:00000000;05:c8ff6b01;06:fc6a6501;07:0c6a6501;08:90e96b01;09:28000000;0a:74a0ea37;0b:c8ff6b01;0c:b09e5b00;0d:086a6501;0e:d1b22000;0f:
> 
> For the first step, a 2 byte memory breakpoint is written to 0x2602e0 
> ($Z0,2602e0,2#73), which is where the first step ended up. The instruction 
> that got replaced is 2 bytes long. The GDB command wrote a 2 bytes memory 
> breakpoint to the address, so all is good.
> 
> For the second step, a 2 byte memory breakpoint is written to 0x2602ea 
> ($Z0,2602ea,2#a4). But instead of ending up at 0x2602ec, which is in the 
> middle of the 4-byte blne instruction.
> 
> Is it correct for LLDB to set a 2 byte memory breakpoint instead of a 4-byte 
> memory breakpoint in this case? The PC will be set to an invalid address, 
> which then causes the EXC_BAD_INSTRUCTION.
> 
> Am i understanding this correctly? Is there a way for me to fix this?
> 
> On Wed, Nov 26, 2014 at 5:26 PM, Mario Zechner <badlogicga...@gmail.com> 
> wrote:
> Hi,
> 
> we generate thumbv7 binaries for iOS devices. We deploy, launch and debug 
> those via LLDB. Stepping into functions seems to almost always generate a 
> EXC_BAD_INSTRUCTION signal. The signal is not generated when running the app 
> without the debugger attached. It is also not generated when we attach a 
> debugger, but simply let the app run without breakpoints or any stepping.
> 
> Here's one of these function's LLVM IR:
> 
> =======================
> define external void @"[J]java.lang.Object.<init>()V"(%Env* %p0, %Object* 
> %p1) nounwind noinline optsize {
> label0:
>     call void @"llvm.dbg.declare"(metadata !{%Env* %p0}, metadata !19), !dbg 
> !{i32 136, i32 0, metadata !{i32 786478, metadata !0, metadata !1, metadata 
> !"[J]java.lang.Object.<init>()V", metadata !"[J]java.lang.Object.<init>()V", 
> metadata !"", i32 136, metadata !15, i1 false, i1 true, i32 0, i32 0, null, 
> i32 256, i1 false, void (%Env*, %Object*)* @"[J]java.lang.Object.<init>()V", 
> null, null, metadata !17, i32 136}, null}
>     %r0 = alloca %Object*
>     store %Object* null, %Object** %r0
>     call void @"llvm.dbg.declare"(metadata !{%Object** %r0}, metadata !21), 
> !dbg !{i32 136, i32 0, metadata !14, null}
>     store %Object* %p1, %Object** %r0
>     call void @"register_finalizable"(%Env* %p0, %Object* %p1), !dbg !{i32 
> 136, i32 0, metadata !18, null}
>     ret void, !dbg !{i32 136, i32 0, metadata !18, null}
> }
> =======================
> 
> The corresponding thumbv7 assembler code as generated by LLVM:
> 
> =======================
>       .globl  "_[J]java.lang.Object.<init>()V"
>       .align  2
>       .code   16                      @ @"[J]java.lang.Object.<init>()V"
>       .thumb_func     "_[J]java.lang.Object.<init>()V"
> "_[J]java.lang.Object.<init>()V":
>       .cfi_startproc
> Lfunc_begin18:
>       .loc    1 136 0                 @ Object.java:136:0
> @ BB#0:                                 @ %label0
>       .loc    1 136 0                 @ Object.java:136:0
>       push    {r7, lr}
>       mov     r7, sp
>       sub     sp, #4
>       @DEBUG_VALUE: [J]java.lang.Object.<init>()V:__$env <- R0
>       movs    r2, #0
>       str     r2, [sp]
>       str     r1, [sp]
>       .loc    1 136 0 prologue_end    @ Object.java:136:0
> Ltmp6:
>       ldr     r2, [r1]
>       ldr     r2, [r2, #48]
>       tst.w   r2, #1048576
> Ltmp7:
>       @DEBUG_VALUE: [J]java.lang.Object.<init>()V:__$env <- R0
>       it      ne
>       blxne   __bcRegisterFinalizer
>       add     sp, #4
>       pop     {r7, pc}
> Ltmp8:
> Lfunc_end18:
> "L_[J]java.lang.Object.<init>()V_end":
> 
>       .cfi_endproc
> =======================
> 
> Now, when stepping into this function, LLDB receives a signal from the debug 
> server:
> 
> =======================
> (lldb) s
> Process 176 stopped
> * thread #1: tid = 0x11f5, 0x0023e2ec 
> AttachTestIOSDev`[J]java.lang.Object.<init>(__$env=0x0169efc8, 
> __$this=0x0174cd10)V + 24 at Object.java:136, queue = 
> 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION 
> (code=EXC_ARM_UNDEFINED, subcode=0xffd1b001)
>     frame #0: 0x0023e2ec 
> AttachTestIOSDev`[J]java.lang.Object.<init>(__$env=0x0169efc8, 
> __$this=0x0174cd10)V + 24 at Object.java:136
> =======================
> 
> Disassembling around the PC gives:
> 
> =======================
> (lldb) disassemble --pc
> AttachTestIOSDev`[J]java.lang.Object.<init>()V + 24 at Object.java:136:
> -> 0x23e2ec:  .long  0xb001ffd1                ; unknown opcode
>    0x23e2f0:  pop    {r7, pc}
> 
> AttachTestIOSDev`[J]java.lang.Object.<init>()V + 30:
>    0x23e2f2:  nop
> 
> Disassembling until the beginning of the frame gives:
> 
> (lldb) disassemble -f
> AttachTestIOSDev`[J]java.lang.Object.<init>()V at Object.java:136:
>    0x23e2d4:  push   {r7, lr}
>    0x23e2d6:  mov    r7, sp
>    0x23e2d8:  sub    sp, #0x4
>    0x23e2da:  movs   r2, #0x0
>    0x23e2dc:  str    r2, [sp]
>    0x23e2de:  str    r1, [sp]
>    0x23e2e0:  ldr    r2, [r1]
>    0x23e2e2:  ldr    r2, [r2, #0x30]
>    0x23e2e4:  tst.w  r2, #0x100000
>    0x23e2e8:  it     ne
>    0x23e2ea:  blne   0x429290                  ; _bcRegisterFinalizer
>    0x23e2ee:  add    sp, #0x4
>    0x23e2f0:  pop    {r7, pc}
> 
> Accprding to this, execution should never end up at address 0x23e2ec. That's 
> right in the middle of the blne and add instructions in the second 
> disassembly. I have a hunch that the debugserver on the device may interfere 
> here, e.g. add a trap instruction to implement the stepping. I'm not quite 
> sure what to make of it.
> 
> I'd appreciate any hints. If you require more information, i got plenty of 
> logs :)
> 
> Thanks,
> Mario
> 
> _______________________________________________
> lldb-dev mailing list
> lldb-dev@cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev


_______________________________________________
lldb-dev mailing list
lldb-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to