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