Again, this is a good analysis of why we are crashing.  But it isn't the right 
solution for stepping.  When we are stepping through the IT & the instructions 
it governs we need to make sure we DON'T try to do the fast-stepping, but just 
use the hardware single step and go instruction by instruction.

Jim

> On Dec 2, 2014, at 2:52 PM, Greg Clayton <gclay...@apple.com> wrote:
> 
> So the nitty gritty details are IT is followed by up  to four "i" for if, or 
> "e" for else.
> 
> 
> So if you have:
> 
> IT ieei
> op1  (if)
> op2  (else)
> op3  (else) 
> op4  (if)
> 
> The if/else bits are stored in the CPSR so it knows that an IT is going on 
> and the condition is stored in some bits and the if/else bits are also stored.
> 
> The processor will evaluate the condition when it hits the IT instruction 
> which sets bits in the CPSR and then it will either execute or not the next 
> instructions (four in this case). So we _must_ have a 4 byte breakpoint 
> opcode as recognized by the CPU pipeline when it wants to skip the 
> instructions. otherwise your 16 bit trap + NOP would count for two of the 
> instructions in the IT block. So if we have:
> 
> IT ieei
> op1_32 (if)
> op2_16 (else)
> op3_16 (else)
> op4_16 (if)
> 
> And we replace the op1_32 with a trap16 + nop16 we would execute:
> 
> IT ieei
> trap16 (if)
> nop16  (else)
> op2_16 (else)
> op3_16 (if)
> op4_16
> 
> So now our if/thens won't work...
> 
> 
> 
>> On Dec 2, 2014, at 2:35 PM, Mario Zechner <badlogicga...@gmail.com> wrote:
>> 
>> I guess the 4-byte instruction could be replaced by a 2-byte trap and a 
>> 2-byte nop (if that exists on ARM). Or any 2-byte instruction instead of the 
>> nop. If i understand correctly, once the trap is hit, the original 4-byte 
>> instruction should be restored again, no? If that's not the case, i could 
>> manually replace the 2nd 2-byte nop with the original 2-bytes after whatever 
>> mechanism restores the memory at the trap location.
>> 
>> I'm still confused why IT isn't considered a branch, i go hit the ARM docs 
>> again :)
>> 
>> On Tue, Dec 2, 2014 at 10:59 PM, Greg Clayton <gclay...@apple.com> wrote:
>> The problem here is that we are modifying a 32 bit instruction with a 16 bit 
>> trap. The "IT" instruction isn't a branch and it shouldn't be considered 
>> one. The solution of using a 4 byte thumb breakpoint must be used and this 
>> will work for Linux, but won't work on MacOSX because our kernel, to my 
>> knowledge doesn't support a 32 bit thumb breakpoint. I will check on this. 
>> So the real fix is to use a 32 bit thumb breakpoint for 32 bit thumb 
>> instructions.
>> 
>> Greg
>> 
>>> On Dec 2, 2014, at 12:01 PM, jing...@apple.com wrote:
>>> 
>>> The question that the stepping code is really asking is "can I predict the 
>>> next instruction that will follow on from this one before I get there."  If 
>>> IsBranch isn't sufficient to know that for some instruction or class of 
>>> instructions, then adding whatever other tests are required seems okay 
>>> formally.  It would be nicer if the MC instructions had some other way to 
>>> characterize this and whatever other instructions behave the same way, but 
>>> I'm not clear enough on what the "way" is to know what question to ask the 
>>> instruction other than "IsBranch".  It would definitely be worth having a 
>>> conversation with the LLVM folks about some way to determine this.  
>>> Otherwise, having to special-case some instructions as "these we know 
>>> confuse us" seems ugly but not terrible.
>>> 
>>> Jim
>>> 
>>> 
>>>> On Dec 2, 2014, at 4:11 AM, Mario Zechner <badlogicga...@gmail.com> wrote:
>>>> 
>>>> Sorry Stephane, forgot to hit "Reply all".
>>>> 
>>>> I dug a bit deeper. The problem is in LLVM's instruction table for ARM 
>>>> Thumbv2. Here's the definition of the IT instruction 
>>>> (llvm/lib/Target/ARM/ARMInstrThumb2.td):
>>>> 
>>>> // IT block
>>>> let Defs = [ITSTATE] in
>>>> def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
>>>>                   AddrModeNone, 2,  IIC_iALUx,
>>>>                   "it$mask\t$cc", "", []>,
>>>>          ComplexDeprecationPredicate<"IT"> {
>>>> // 16-bit instruction.
>>>> let Inst{31-16} = 0x0000;
>>>> let Inst{15-8} = 0b10111111;
>>>> 
>>>> bits<4> cc;
>>>> bits<4> mask;
>>>> let Inst{7-4} = cc;
>>>> let Inst{3-0} = mask;
>>>> 
>>>> let DecoderMethod = "DecodeIT";
>>>> }
>>>> 
>>>> The instruction isn't marked as isBranch (e.g. via let isBranch=1).
>>>> 
>>>> ThreadPlanStepRange retrieves the next branch instruction for an address 
>>>> range via InstructionList::GetIndexOfNextBranchInstruction, which uses a 
>>>> Disassembler instance that gets all the instruction info from that 
>>>> tablegen file (through the llvm::Target). For each 
>>>> lldb_private::Instruction in the list InstructionLLVMC::DoesBranch is 
>>>> called, which in turn calls 
>>>> DisassemblerLLVMC::LLVMCDisassembler::CanBranch. That method looks up the 
>>>> MCInstrDesc for the instruction's opcode. That MCInstrDesc has a Flag 
>>>> member, which comes from the tablegen file. That is set to 
>>>> MCID::UnmodeledSideEffects for the IT instruction, which is why it's not 
>>>> selected as the next branch instruction.
>>>> 
>>>> Now, i have no idea what side effects it would have to change the tablegen 
>>>> file and regenerate the table. My guess would be that it's a bad idea to 
>>>> change that 4.7k LOC .td file and hope for the best. I guess i'll manually 
>>>> check for the IT instruction in 
>>>> InstructionList::GetIndexOfNextBranchInstruction in case the target arch 
>>>> is ARM. That seems like a really dirty hack though.
>>>> 
>>>> Any other ideas? Is this something that should be brought up with the LLVM 
>>>> guys?
>>>> 
>>>> On Tue, Dec 2, 2014 at 1:10 PM, Mario Zechner <badlogicga...@gmail.com> 
>>>> wrote:
>>>> I dug a bit deeper. The problem is in LLVM's instruction table for ARM 
>>>> Thumbv2. Here's the definition of the IT instruction 
>>>> (llvm/lib/Target/ARM/ARMInstrThumb2.td):
>>>> 
>>>> // IT block
>>>> let Defs = [ITSTATE] in
>>>> def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
>>>>                   AddrModeNone, 2,  IIC_iALUx,
>>>>                   "it$mask\t$cc", "", []>,
>>>>          ComplexDeprecationPredicate<"IT"> {
>>>> // 16-bit instruction.
>>>> let Inst{31-16} = 0x0000;
>>>> let Inst{15-8} = 0b10111111;
>>>> 
>>>> bits<4> cc;
>>>> bits<4> mask;
>>>> let Inst{7-4} = cc;
>>>> let Inst{3-0} = mask;
>>>> 
>>>> let DecoderMethod = "DecodeIT";
>>>> }
>>>> 
>>>> The instruction isn't marked as isBranch (e.g. via let isBranch=1).
>>>> 
>>>> ThreadPlanStepRange retrieves the next branch instruction for an address 
>>>> range via InstructionList::GetIndexOfNextBranchInstruction, which uses a 
>>>> Disassembler instance that gets all the instruction info from that 
>>>> tablegen file (through the llvm::Target). For each 
>>>> lldb_private::Instruction in the list InstructionLLVMC::DoesBranch is 
>>>> called, which in turn calls 
>>>> DisassemblerLLVMC::LLVMCDisassembler::CanBranch. That method looks up the 
>>>> MCInstrDesc for the instruction's opcode. That MCInstrDesc has a Flag 
>>>> member, which comes from the tablegen file. That is set to 
>>>> MCID::UnmodeledSideEffects for the IT instruction, which is why it's not 
>>>> selected as the next branch instruction.
>>>> 
>>>> Now, i have no idea what side effects it would have to change the tablegen 
>>>> file and regenerate the table. My guess would be that it's a bad idea to 
>>>> change that 4.7k LOC .td file and hope for the best. I guess i'll manually 
>>>> check for the IT instruction in 
>>>> InstructionList::GetIndexOfNextBranchInstruction in case the target arch 
>>>> is ARM. That seems like a really dirty hack though.
>>>> 
>>>> Any other ideas? Is this something that should be brought up with the LLVM 
>>>> guys?
>>>> 
>>>> On Mon, Dec 1, 2014 at 7:55 PM, Stephane Sezer <s...@fb.com> wrote:
>>>> I suppose it wouldn’t get hit, no. I don’t know about considering it 
>>>> instructions as a branching instruction. I guess it makes sense but I 
>>>> don’t know how the rest would work with it.
>>>> 
>>>> --
>>>> Stephane Sezer
>>>> 
>>>>> On Dec 1, 2014, at 10:47 AM, Mario Zechner <badlogicga...@gmail.com> 
>>>>> wrote:
>>>>> 
>>>>> Thanks, i'm going to try that. I just wonder if it would make more sense 
>>>>> to consider the it instruction a branching instruction. Not sure what 
>>>>> side effects that may have.
>>>>> 
>>>>> Also, if i wrote a 4-byte breakpoint for blne, would it get hit if the it 
>>>>> branches over it? Guess i'll find out :)
>>>>> 
>>>>> On Dec 1, 2014 6:46 PM, "Stephane Sezer" <s...@fb.com> wrote:
>>>>> I remember fighting with this recently in our debug server (ds2), your 
>>>>> understanding of the problem is correct I believe. What you need to do is 
>>>>> to place a four-byte thumb breakpoint instead of a two-byte thumb 
>>>>> breakpoint. I don’t know what the iOS kernel expects exactly, but for 
>>>>> example the Linux kernel understands the following:
>>>>> - two-byte thumb breakpoint: 0xde01
>>>>> - four-byte thumb breakpoint: 0xa000f7f0
>>>>> - arm breakpoint: 0xe7f001f0
>>>>> 
>>>>> If you insert a four-byte thumb breakpoint at 0x27b2ea, the it 
>>>>> instruction will skip four bytes when skipping the breakpoint, and will 
>>>>> end up at address 0x27b2ee, which is what you would expect.
>>>>> 
>>>>> --
>>>>> Stephane Sezer
>>>>> 
>>>>>> On Dec 1, 2014, at 8:13 AM, Mario Zechner <badlogicga...@gmail.com> 
>>>>>> wrote:
>>>>>> 
>>>>>> I think i understand the issue now. 
>>>>>> ThreadPlanStepRange::SetNextBranchBreakpoint is falsely selecting the 
>>>>>> blne instruction instead of the it instruction. The condition is not 
>>>>>> meet, so the CPU jumps over the instruction after it. Since we have a 
>>>>>> trap there that's 2 bytes long, it will end up at 0x27b2ec (PC after 2 
>>>>>> byte trap instruction) instead of 0x27b2ee (PC after 4 byte blne). So 
>>>>>> the CPU ends up in the middle of the blne instruction, which is of 
>>>>>> course not a valid instruction.
>>>>>> 
>>>>>> I guess the next thing i have to figure out is why the it instruction 
>>>>>> isn't marked as a branch instruction, which is why it isn't selected by 
>>>>>> ThreadPlanStepRange::SetNextBranchBreakpoint as the next branch 
>>>>>> breakpoint.
>>>>>> 
>>>>>> On Mon, Dec 1, 2014 at 4:59 PM, Mario Zechner <badlogicga...@gmail.com> 
>>>>>> wrote:
>>>>>> I traced through ThreadPlanStepRange and ThreadPlanStepRange for this 
>>>>>> piece of code:
>>>>>> 
>>>>>> 0x27b2d4 <[J]java.lang.Object.<init>()V>: push   {r7, lr}
>>>>>> 
>>>>>> 0x27b2d6 <[J]java.lang.Object.<init>()V+2>: mov    r7, sp
>>>>>> 
>>>>>> 0x27b2d8 <[J]java.lang.Object.<init>()V+4>: sub    sp, #0x4
>>>>>> 
>>>>>> 0x27b2da <[J]java.lang.Object.<init>()V+6>: movs   r2, #0x0
>>>>>> 
>>>>>> 0x27b2dc <[J]java.lang.Object.<init>()V+8>: str    r2, [sp]
>>>>>> 
>>>>>> 0x27b2de <[J]java.lang.Object.<init>()V+10>: str    r1, [sp]
>>>>>> 
>>>>>> 0x27b2e0 <[J]java.lang.Object.<init>()V+12>: ldr    r2, [r1]
>>>>>> 
>>>>>> 0x27b2e2 <[J]java.lang.Object.<init>()V+14>: ldr    r2, [r2, #0x30]
>>>>>> 
>>>>>> 0x27b2e4 <[J]java.lang.Object.<init>()V+16>: tst.w  r2, #0x100000
>>>>>> 
>>>>>> 0x27b2e8 <[J]java.lang.Object.<init>()V+20>: it     ne
>>>>>> 
>>>>>> 0x27b2ea <[J]java.lang.Object.<init>()V+22>: blne   0x466290             
>>>>>>      ; _bcRegisterFinalizer
>>>>>> 
>>>>>> 0x27b2ee <[J]java.lang.Object.<init>()V+26>: add    sp, #0x4
>>>>>> 
>>>>>> 0x27b2f0 <[J]java.lang.Object.<init>()V+28>: pop    {r7, pc}
>>>>>> 
>>>>>> 0x27b2f2 <[J]java.lang.Object.<init>()V+30>: nop
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> Execution is halted at 0x27b2e0 when i issue a source-level step. The 
>>>>>> ThreadPlanStepRange::DidPush method sets up a breakpoint at 0x27b2ea (2 
>>>>>> bytes) successfully after identifying the instruction at 0x27b2ea (blne) 
>>>>>> as the next branch instruction in 
>>>>>> ThreadPlanStepRange::SetNextBranchBreakpoint.
>>>>>> 
>>>>>> Next, the threads are then resumed by the command interpreter. We 
>>>>>> receive an event from the inferior with stop reason eStopReasonException 
>>>>>> (EXC_BAD_INSTRUCTION) right after the resume, stopping the process.
>>>>>> 
>>>>>> I guess this means i need to figure out how "it" and "blne" work 
>>>>>> together (my ARM assembler knowledge is minimal) to then understand why 
>>>>>> the breakpoint instruction that's written to the inferior results in a 
>>>>>> EXC_BAD_INSTRUCTION. If someone knows what could be the culprit let me 
>>>>>> know :)
>>>>>> 
>>>>>> Thanks,
>>>>>> 
>>>>>> Mario
>>>>>> 
>>>>>> 
>>>>>> On Mon, Dec 1, 2014 at 2:07 PM, Mario Zechner <badlogicga...@gmail.com> 
>>>>>> wrote:
>>>>>> Well, i wrote a very long mail detailing my journey to resolve issue #2 
>>>>>> (hanging after setting target.use-fast-stepping=false), only to 
>>>>>> eventually realize that it doesn't hang but instead just waits for the 
>>>>>> above loop to complete.
>>>>>> 
>>>>>> This means turning off target.use-fast-stepping is not an option and i'm 
>>>>>> back to square one. I'd be grateful for any pointers on how to fix issue 
>>>>>> #1 (EXC_BAD_INSTRUCTION). I guess i'll start by investigating the "run 
>>>>>> to next branch" stepping algorithm in LLDB, though my understanding is 
>>>>>> likely not sufficient to make a dent.
>>>>>> 
>>>>>> Thanks,
>>>>>> Mario
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> On Mon, Dec 1, 2014 at 11:05 AM, Mario Zechner <badlogicga...@gmail.com> 
>>>>>> wrote:
>>>>>> Hi,
>>>>>> 
>>>>>> setting target.use-fast-stepping to false did indeed solve this issue, 
>>>>>> albeit at the cost of increased runtime obviously. However, i ran into 
>>>>>> another issue right after i stepped out of the previously problematic 
>>>>>> function: http://sht.tl/bdAKRC
>>>>>> 
>>>>>> Trying to source-level step this function (with use-fast-stepping=false) 
>>>>>> results in 1) the disassembly getting all kinds of messed up and 2) the 
>>>>>> process not stepping but hanging at the `cmp r1, #0` instruction. The 
>>>>>> original assembly code around that PC looks like this:
>>>>>> 
>>>>>> LBB24_1:                                @ %label0
>>>>>>                                       @ =>This Inner Loop Header: Depth=1
>>>>>>     @DEBUG_VALUE: 
>>>>>> [J]java.lang.Thread.<init>(Ljava/lang/Runnable;Ljava/lang/String;)V:__$env
>>>>>>  <- R5
>>>>>>     ldrexd  r1, r2, [r0]
>>>>>>     strexd  r1, r6, r6, [r0]
>>>>>>     cmp     r1, #0
>>>>>>     bne     LBB24_1
>>>>>> @ BB#2:                                 @ %label0
>>>>>>     @DEBUG_VALUE: 
>>>>>> [J]java.lang.Thread.<init>(Ljava/lang/Runnable;Ljava/lang/String;)V:__$env
>>>>>>  <- R5
>>>>>>     dmb     ish
>>>>>>     movs    r1, #5
>>>>>> 
>>>>>> A simple loop, which is actually part of an inlined function. We had 
>>>>>> some issues with inlined functions previously, i assume this issue is 
>>>>>> related. Interestingly enough, the back trace is also a bit wonky:
>>>>>> 
>>>>>> (lldb) bt
>>>>>> 
>>>>>> * thread #1: tid = 0x18082, 0x0021a9b4 
>>>>>> AttachTestIOSDev`[J]java.lang.Thread.<init>(Ljava/lang/Runnable;Ljava/lang/String;)V
>>>>>>  [inlined] [j]java.lang.Thread.threadPtr(J)[set] + 14 at Thread.java:1, 
>>>>>> stop reason = trace
>>>>>> 
>>>>>> * frame #0: 0x0021a9b4 
>>>>>> AttachTestIOSDev`[J]java.lang.Thread.<init>(Ljava/lang/Runnable;Ljava/lang/String;)V
>>>>>>  [inlined] [j]java.lang.Thread.threadPtr(J)[set] + 14 at Thread.java:1
>>>>>> 
>>>>>>   frame #1: 0x0021a9a6 
>>>>>> AttachTestIOSDev`[J]java.lang.Thread.<init>(__$env=0x01662fc8, 
>>>>>> __$this=0x64da3833, runnable=0xa4f07400, threadName=0x00286000)V + 46 at 
>>>>>> Thread.java:138
>>>>>> 
>>>>>> There should be a lot more frame. I'm gonna try to dig up some more 
>>>>>> details.
>>>>>> 
>>>>>> Thanks a lot!
>>>>>> Mario
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> On Sun, Nov 30, 2014 at 1:32 AM, Jason Molenda <ja...@molenda.com> wrote:
>>>>>> 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
>>>>>> https://urldefense.proofpoint.com/v1/url?u=http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev&k=ZVNjlDMF0FElm4dQtryO4A%3D%3D%0A&r=g1GoAnQQskSBaWLJWw6X6w%3D%3D%0A&m=Zl2rgz3vY3p3Z1gT4mYUogC%2B71s1vpu6iiR2%2BAqSFEs%3D%0A&s=3063d588fdc99fda75142f80da681ac13b53ba823de3e2221c1b01c0c7c54982
>>>>> 
>>>> 
>>>> 
>>>> 
>>>> _______________________________________________
>>>> 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
> 


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

Reply via email to