square / pylink

Python Library for device debugging/programming via J-Link
https://pylink.readthedocs.io/en/latest/
Other
344 stars 127 forks source link

JLinkMOEInfo Index always -1 for code breakpoints #44

Open mtport opened 5 years ago

mtport commented 5 years ago

I use pylink on a Ubuntu 18 64bit and an R7FS7G27H (Renesas Synergy) core via the integrated USB debug interface of the Synergy device. Everything works fine except a problem with breakpoints. To work with breakpoints, the breakpoint is set via breakpoint_set which returns a valid handle. I then run the program until halted() returns true. Then the reason for the halt is retrieved via cpu_halt_reasons(). The instance of JLinkMOEInfo returns True for code_breakpoint(), but always contains -1 for Index. Is there a way to retrieve which breakpoint was triggered?

hkpeprah commented 5 years ago

So the handle and index are different. Is the breakpoint active if you call num_active_breakpoints()? If this is a software breakpoint, did you enable breakpoints by calling enable_soft_breakpoints()?

mtport commented 5 years ago

num_active_breakpoints returns 2 which is the correct number of breakpoints set. I also tried to use software_breakpoint_set (and also called enable_soft_breakpoints) with the same result. Some breakpoint is hit but Index always returns -1. Just for info, the installed SEGGER JLink software package is v6.32h 64bit.

AbdelrahmanAshraf98 commented 7 months ago

I Have the same Issue , any updates ?

hkpeprah commented 7 months ago

Hm. Sorry. I haven't looked too much into this. Maybe as a workaround, you could read the $PC via register_read(), and use that to lookup the breakpoint via breakpoint_find(), which would give you the handle to use with breakpoint_info()? E.g.

pc = jl.register_read(index_of_pc)
handle = jl.breakpoint_find(pc)
if handle > 0:
    info = jl.breakpoint_info(handle)
    <...>

Though I'm not sure what you need the index for. Could you describe more that use case?

AbdelrahmanAshraf98 commented 7 months ago

I want to make sure which breakpoint the CPU is halted at, I added 3 breakpoints and each time I want to check that the CPU is halted at the expected breakpoint.

hkpeprah commented 7 months ago

I would try the above and see if that works for your use case. You should be able to compare the handle against the handle(s) you got when you created the breakpoint.

AbdelrahmanAshraf98 commented 7 months ago

Yes , this is exactly what I need to do , I created a breakpoint dictionary that contains all the added breakpoints handles and I expected to get the breakpoint handle from cpu_halt_reasons() to compare and assert but it didn't work .

hkpeprah commented 7 months ago

The cpu_halt_reasons structures don't have the handles, only the index in the breakpoint list. I would try using the address that the CPU is halted on to try and see if there is a breakpoint set there, then use that to get the handle like the above snippet I posted.

AbdelrahmanAshraf98 commented 7 months ago

how to get the address the CPU is halted on ?

hkpeprah commented 7 months ago

Say you're on an ARM Cortex-M33, then your register list is this: image PC or Program Counter is R15, and indicates the current address of execution. So if you pass in:

pc = jl.register_read(15)

then pc would be the address the CPU is halted on.

AbdelrahmanAshraf98 commented 7 months ago

Thanks a lot for you help, I will try this and give you my feedback again

AbdelrahmanAshraf98 commented 6 months ago

It Works with me, Thank you .

hkpeprah commented 6 months ago

Good to hear!

AbdelrahmanAshraf98 commented 6 months ago

Hello @hkpeprah , I want to ask two more questions not related to this thread please, 1- I want to know if I can continue run after being halted at breakpoint but without removing the breakpoint ? 2- how can I read local variables ?

Thanks for your help

hkpeprah commented 6 months ago
  1. You can use restart() and pass skip_breakpoints=True; see documentation here.
  2. Reading local variables is tricky. You need to know what the compiled assembly is to see if the variables are on the stack, or in a register, and if in a register, what specific register it is. If you know the calling convention for your architecture, and your breakpoint is on a function, then it's a bit easier. Otherwise, you need to look at the generated assembly to see where the variable was placed.
AbdelrahmanAshraf98 commented 6 months ago

restart() didn't work with me , my scenario is that I need to add 2 breakpoints then after halt I need to continue running to halt on the second breakpoint

hkpeprah commented 6 months ago

I would play around with the arguments to restart() if you haven't yet; I think restart(num_instructions=1, skip_breakpoints=True) should continue on by jumping over the breakpoint instruction, and continue running your firmware.

AbdelrahmanAshraf98 commented 6 months ago

Actually I haven't used num_instructions param, I will Check This.

AbdelrahmanAshraf98 commented 1 month ago

Hello hkpeprah, after I tried use num_instructions It doesn't work.

I trying to use Go command after being halted on breakpoint with out the need to delete this breakpoint.

  1. Add breakpoint
  2. Go (restart)
  3. Check if the PC register and if the cpu is halted on the right place.
  4. Go (restart) and Continue the scenario to another breakpoints
hkpeprah commented 1 month ago

Do you have sample code? I can fire it up with two breakpoints against one of my local targets and see, but my target would likely not be the same ARM or RISC target that you're debugging with.