Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breakpoint causes unhandled exeception #1409

Closed
wd5gnr opened this issue Jun 7, 2022 · 11 comments · Fixed by #1428
Closed

Breakpoint causes unhandled exeception #1409

wd5gnr opened this issue Jun 7, 2022 · 11 comments · Fixed by #1428
Labels

Comments

@wd5gnr
Copy link

wd5gnr commented Jun 7, 2022

Setup: ST-Link v2 with an STM32F411CE. Setup works with Mbed Studio (which uses pyOCD). However, trying to use pyOCD without studio -- either the version included or the latest version -- causes a failure when gdb sets a breakpoint. I have tried both the stripped down pack included with Mbed Studio and the full pack. I've tried remote and extended remote. I've try gdb-multiarch and the arm noabi gdb. All the same results.

The exact same setup works fine with OpenOCD so I think wiring etc isn't the issue.

When I try to set a breakpoint I get:

0012712 E Unhandled exception in handle_message (b'm'): result size (6) != requested size (4) [gdbserver]
Traceback (most recent call last):
  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 423, in handle_message
    reply = handler(msg[msgStart:])

  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 844, in get_memory
    mem = self.target_context.read_memory_block8(addr, length)

  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/debug/cache.py", line 42, in read_memory_block8
    return self._memcache.read_memory_block8(addr, size)

  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/cache/memory.py", line 258, in read_memory_block8
    assert len(result) == size, "result size ({}) != requested size ({})".format(len(result), size)

AssertionError: result size (6) != requested size (4)

0012712 E Unexpected exception: a bytes-like object is required, not 'tuple' [gdbserver]

Traceback (most recent call last):

  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 390, in _run_connection
    self.packet_io.send(resp)

  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/packet_io.py", line 83, in send
    self._write_packet(packet)

  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/packet_io.py", line 146, in _write_packet
    written = self._abstract_socket.write(packet)

  File "/home/alw/.local/lib/python3.8/site-packages/pyocd/utility/sockets.py", line 58, in write
    return self.conn.send(data)

TypeError: a bytes-like object is required, not 'tuple'

I feel like I must be doing something wrong. I've tried simple invocations and trying to mimic the Mbed Studio invocation. So:

pyocd gdbserver -t stm32f411ce

Along with explicit pack definitions. Also

python3 -mpyocd gdbserver --target STM32F411CE --erase=chip --frequency 1800000 --pack '/home/alw/.config/Mbed Studio/mbed-studio-tools/cmsis-packs/Keil.STM32F4xx_DFP.2.15.0-small.pack' -O connect_mode=under-reset -O enable_swv=1 -O swv_system_clock=96000000 -O swv_raw_port=3443 -O swv_clock=2000000

And many variations (e.g., no swv, etc.).

@Hoohaha
Copy link
Contributor

Hoohaha commented Jun 8, 2022

I am facing this issue too within gdbserver. but during load with custom target.

@wd5gnr
Copy link
Author

wd5gnr commented Jun 8, 2022

@Hoohaha Do you mean when executing load? Are you using remote or extended-remote in the target specifier? It does change the error depending on which way I try, but in my case seems to always be when a breakpoint is set or when you try to run (and, presumably, it tries to write the breakpoint).

@Hoohaha
Copy link
Contributor

Hoohaha commented Jun 9, 2022

When an unexpected exception happened, the gdbserver will be crashed and report TypeError: a bytes-like object is required, not 'tuple'. So I confused yesyerday. Finaly I found it is caused by wrong flash ago configuration. So it always failed during loading program.

In your case, seems failed when read memory, I have no idea for that.

@wd5gnr
Copy link
Author

wd5gnr commented Jun 9, 2022

Can you elaborate on how your flash was misconvigured? I also get the tuple message after the initial message.

@flit
Copy link
Member

flit commented Jun 10, 2022

Thanks for the report! It's pretty clearly a bug in pyocd. Not sure why it didn't show up in CI, since breakpoints in gdb are tested. I'll take a look at it this weekend.

@flit flit added the bug label Jun 10, 2022
@flit
Copy link
Member

flit commented Jun 10, 2022

@wd5gnr The "AssertionError: result size (6) != requested size (4)" seems to be the root cause. This spills down and causes a further exception because the gdbserver somehow handles it wrong. You're not doing anything wrong! 😄

The main question is why the data cache sees an incorrect size. It might be caused by attempting to read at the boundary of a memory region, such that 2 bytes are clipped off.

I'll need a gdbserver debug log, and ideally a copy of the firmware .elf if you can provide it (or an equivalent reproducer .elf). To get the debug log, run with -vv -Lpyocd.gdbserver.*.trace*=debug on the pyocd command line. This can produce a lot of data, so you might want to redirect to a file with 2> pyocd.log. (Only stderr is needed.)

If you can provide the ELF file, you can send to me via email (please see my GitHub profile for my email address) or attach to a comment here.

@wd5gnr
Copy link
Author

wd5gnr commented Jun 10, 2022

I'm going to zip together some full log files and also the elf file for you, but here's a quick excerpt:

026624 D GDB getMem: addr=8004398 len=2 [gdbserver]
0026625 D --<<<< GDB send 8 bytes: b'$2846#d4' [packet_io]
0026625 D -->>>> GDB read 16 bytes: b'$Z1,8004398,2#85' [packet_io]
0026625 D GDB breakpoint b'Z'1 @ 8004398 [gdbserver]
0026625 D set bkpt type HW at 0x8004398 [manager]
0026625 D using hw bp instead because addr is flash [manager]
0026625 D selected bkpt type HW for addr 0x8004398 [manager]
0026625 D using hw bp instead because addr is flash [manager]
0026625 D selected bkpt type HW for addr 0x8004378 [manager]
0026625 D --<<<< GDB send 6 bytes: b'$OK#9a' [packet_io]
0026625 D -->>>> GDB read 10 bytes: b'$vCont?[#49](https://github.com/pyocd/pyOCD/pull/49)' [packet_io]
0026625 D --<<<< GDB send 21 bytes: b'$vCont;c;C;s;S;r;t#be' [packet_io]
0026625 D -->>>> GDB read 11 bytes: b'$vCont;c#a8' [packet_io]
0026627 E Unhandled exception in handle_message (b'v'): result size (4) != requested size (1) [gdbserver]
Traceback (most recent call last):
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 423, in handle_message
reply = handler(msg[msgStart:])
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 710, in v_command
return self.v_cont(cmd)
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 728, in v_cont
if self.is_threading_enabled():
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 1220, in is_threading_enabled
return (self.thread_provider is not None) and self.thread_provider.is_enabled \
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/rtos/rtx5.py", line 409, in is_enabled
return self.get_kernel_state() != 0 and not self._target.in_thread_mode_on_main_stack()
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/rtos/rtx5.py", line 447, in get_kernel_state
return self._target_context.read8(self._os_rtx_info + RTX5ThreadProvider.KERNEL_STATE_OFFSET)
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/core/memory_interface.py", line 156, in read8
return self.read_memory(addr, 8, now)
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/debug/cache.py", line 33, in read_memory
return self._memcache.read_memory(addr, transfer_size, now)
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/cache/memory.py", line 230, in read_memory
data = self.read_memory_block8(addr, 1)[0]
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/cache/memory.py", line 258, in read_memory_block8
assert len(result) == size, "result size ({}) != requested size ({})".format(len(result), size)
AssertionError: result size (4) != requested size (1)
0026628 D --<<<< GDB send 2 bytes: (b'$E01#a6', 0) [packet_io]
0026628 E Unexpected exception: a bytes-like object is required, not 'tuple' [gdbserver]
Traceback (most recent call last):
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/gdbserver.py", line 390, in _run_connection
self.packet_io.send(resp)
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/packet_io.py", line 83, in send
self._write_packet(packet)
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/gdbserver/packet_io.py", line 146, in _write_packet
written = self._abstract_socket.write(packet)
File "/home/alw/.local/lib/python3.8/site-packages/pyocd/utility/sockets.py", line 58, in write
return self.conn.send(data)
TypeError: a bytes-like object is required, not 'tuple'
0029613 D -->>>> GDB read 1 bytes: b'\x03' [packet_io]
0033612 D GDB packet thread: other side closed connection [packet_io]

@wd5gnr
Copy link
Author

wd5gnr commented Jun 10, 2022

Here's a full package. It is hard to say, but I think maybe pyocd doesn't do extended-remote gdbserver? I ran it both ways in case. Also, in some of the runs the chip was already flashed. In some I flashed with gdb and some I flashed with monitor load. The flashes appear successful since the device will run when reset.
package.zip

The zip has a very simple ELF along with full.txt which has a gdb transcript, command line, and the error log. The other files have a bit less info but are also logs.

@flit
Copy link
Member

flit commented Jun 11, 2022

Thanks very much!

Pyocd does support extended-remote. This makes the server persistent, and adds support for the restart command.

flit added a commit to flit/pyOCD that referenced this issue Jun 11, 2022
Don't return the detach value, which was removed in 17ab710.
This fixes one of the issues reported in pyocd#1409.
flit added a commit that referenced this issue Jun 26, 2022
* gdbserver: correct return type from ._handle_message() on exceptions

Don't return the detach value, which was removed in 17ab710.
This fixes one of the issues reported in #1409.

* gdbserver: replace GDBError exceptions with logs

- .handle_query_xml() returns the correct empty packet or error instead
of raising GDBError.
- .get_symbol() logs the error and returns None to the caller.

* gdbserver: qXfer command fixes

- Restructure code to always call into .handle_query_xml() for qXfer
read commands.
- Return empty packet on unknown qXfer operation.
- Pass annex to .handle_query_xml().
- Explicit check for read features annex being 'target.xml', and that
the annex is empty for other objects.
flit added a commit to flit/pyOCD that referenced this issue Jun 26, 2022
* gdbserver: correct return type from ._handle_message() on exceptions

Don't return the detach value, which was removed in 17ab710.
This fixes one of the issues reported in pyocd#1409.

* gdbserver: replace GDBError exceptions with logs

- .handle_query_xml() returns the correct empty packet or error instead
of raising GDBError.
- .get_symbol() logs the error and returns None to the caller.

* gdbserver: qXfer command fixes

- Restructure code to always call into .handle_query_xml() for qXfer
read commands.
- Return empty packet on unknown qXfer operation.
- Pass annex to .handle_query_xml().
- Explicit check for read features annex being 'target.xml', and that
the annex is empty for other objects.
@maxgerhardt
Copy link

maxgerhardt commented Jun 29, 2022

Same issues here with result size != requested size. Using PyOCD's latest Git version with a STLink V3 and an arbitrary mbed-os (aka, RTX5-enabled) firmware on a STM32L476RG, PyOCD implodes.

0104860 E Unhandled exception in handle_message (b'q'): result size (4) != requested size (1) [gdbserver]
Traceback (most recent call last):
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/gdbserver/gdbserver.py", line 419, in handle_message
    reply = handler(msg[msgStart:])
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/gdbserver/gdbserver.py", line 936, in handle_query
    resp = self.handle_query_xml(query[1], query[3], int(data[0], 16), int(data[1].split(b'#')[0], 16))
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/gdbserver/gdbserver.py", line 1110, in handle_query_xml
    xml = self.get_threads_xml()
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/gdbserver/gdbserver.py", line 1202, in get_threads_xml
    if not self.is_threading_enabled():
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/gdbserver/gdbserver.py", line 1222, in is_threading_enabled
    return (self.thread_provider is not None) and self.thread_provider.is_enabled \
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/rtos/rtx5.py", line 409, in is_enabled
    return self.get_kernel_state() != 0 and not self._target.in_thread_mode_on_main_stack()
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/rtos/rtx5.py", line 447, in get_kernel_state
    return self._target_context.read8(self._os_rtx_info + RTX5ThreadProvider.KERNEL_STATE_OFFSET)
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/core/memory_interface.py", line 156, in read8
    return self.read_memory(addr, 8, now)
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/debug/cache.py", line 33, in read_memory
    return self._memcache.read_memory(addr, transfer_size, now)
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/cache/memory.py", line 230, in read_memory
    data = self.read_memory_block8(addr, 1)[0]
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/cache/memory.py", line 258, in read_memory_block8
    assert len(result) == size, "result size ({}) != requested size ({})".format(len(result), size)
AssertionError: result size (4) != requested size (1)

Setting the -O "rtos.enable=false" option, PyOCD crashes in a different way :(

0006431 E Unhandled exception in handle_message (b'm'): result size (4) != requested size (2) [gdbserver]
Traceback (most recent call last):
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/gdbserver/gdbserver.py", line 419, in handle_message
    reply = handler(msg[msgStart:])
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/gdbserver/gdbserver.py", line 840, in get_memory
    mem = self.target_context.read_memory_block8(addr, length)
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/debug/cache.py", line 42, in read_memory_block8
    return self._memcache.read_memory_block8(addr, size)
  File "/home/akurei/.local/lib/python3.10/site-packages/pyocd/cache/memory.py", line 258, in read_memory_block8
    assert len(result) == size, "result size ({}) != requested size ({})".format(len(result), size)
AssertionError: result size (4) != requested size (2)

This is when paired with arm-none-eabi-gdb 10 q4 major.

@flit
Copy link
Member

flit commented Jul 5, 2022

@maxgerhardt Thanks for the additional info!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants