Skip to content

Add support for x packet#186

Open
dblnz wants to merge 1 commit intodaniel5151:masterfrom
dblnz:feat/add-x-packet-support
Open

Add support for x packet#186
dblnz wants to merge 1 commit intodaniel5151:masterfrom
dblnz:feat/add-x-packet-support

Conversation

@dblnz
Copy link

@dblnz dblnz commented Feb 9, 2026

Description

This PR implements the x packet, based off the GDB documentation here.

Closes #163

  • I am not sure whether this needs to be in the base category because the spec specifies it only being supported if the qSupported command marks binary-upload as supported
  • Furthermore, I've only managed to make lldb run a single x command with addr 0 and len 0. I'll give it another try but I am not familiar with LLDB that much.
  • Gdb didn't use x by default

API Stability

  • This PR does not require a breaking API change (I am not 100% sure)

Checklist

  • Documentation
    • Ensured any public-facing rustdoc formatting looks good (via cargo doc)
    • (if appropriate) Added feature to "Debugging Features" in README.md
  • Validation
    • Included output of running examples/armv4t with RUST_LOG=trace + any relevant GDB output under the "Validation" section below
    • Included output of running ./example_no_std/check_size.sh before/after changes under the "Validation" section below
  • If implementing a new protocol extension IDET
    • Included a basic sample implementation in examples/armv4t
    • IDET can be optimized out (confirmed via ./example_no_std/check_size.sh)
    • OR implementation requires introducing non-optional binary bloat (please elaborate under "Description")
  • If upstreaming an Arch implementation
    • I have tested this code in my project, and to the best of my knowledge, it is working as intended.

Validation

LLDB output
(lldb) gdb-remote localhost:9001
Process 1 stopped
* thread #1, stop reason = signal SIGTRAP
       frame #0: 0x55550000
->  0x55550000: str    r11, [sp, #-0x4]!
    0x55550004: add    r11, sp, #0
    0x55550008: sub    sp, sp, #20
    0x5555000c: mov    r3, #4
(lldb) l
note: No source available
(lldb) x/4tw 0x5554FF00
0x5554ff00: 0b00000000000000000000000000000000
0x5554ff04: 0b00000000000000000000000000000000
0x5554ff08: 0b00000000000000000000000000000000
0x5554ff0c: 0b00000000000000000000000000000000
(lldb) x/4tw 0x55503000
0x55503000: 0b00000000000000000000000000000000
0x55503004: 0b00000000000000000000000000000000
0x55503008: 0b00000000000000000000000000000000
0x5550300c: 0b00000000000000000000000000000000
(lldb) x/4tw 0x55548000
0x55548000: 0b00000000000000000000000000000000
0x55548004: 0b00000000000000000000000000000000
0x55548008: 0b00000000000000000000000000000000
0x5554800c: 0b00000000000000000000000000000000
(lldb) x/4tw 0x5554F800
0x5554f800: 0b00000000000000000000000000000000
0x5554f804: 0b00000000000000000000000000000000
0x5554f808: 0b00000000000000000000000000000000
0x5554f80c: 0b00000000000000000000000000000000
(lldb) x/4tw 0x5554FC00
0x5554fc00: 0b00000000000000000000000000000000
0x5554fc04: 0b00000000000000000000000000000000
0x5554fc08: 0b00000000000000000000000000000000
0x5554fc0c: 0b00000000000000000000000000000000
(lldb) x/4tw 0x55550400
0x55550400: 0b00000000000000000000000000000000
0x55550404: 0b00000000000000000000000000000000
0x55550408: 0b00000000000000000000000000000000
0x5555040c: 0b00000000000000000000000000000000
(lldb) c
Process 1 resuming
Process 1 exited with status = -1 (0xffffffff) lost connection
(lldb) q
armv4t output
loading section ".text" into memory from [0x55550000..0x55550078]
Setting PC to 0x55550000
Waiting for a GDB connection on "127.0.0.1:9001"...
Debugger connected from 127.0.0.1:57818
 TRACE gdbstub::protocol::recv_packet > <-- +
 TRACE gdbstub::protocol::recv_packet > <-- $QStartNoAckMode#b0
 TRACE gdbstub::protocol::response_writer > --> $OK#9a
 TRACE gdbstub::protocol::recv_packet     > <-- +
 TRACE gdbstub::protocol::recv_packet     > <-- $qSupported:xmlRegisters=i386,arm,mips,arc;multiprocess+;fork-events+;vfork-events+;swbreak+;hwbreak+#cd
 TRACE gdbstub::protocol::response_writer > --> $PacketSize=1000;vContSupported+;multiprocess+;QStartNoAckMode+;fork-events+;vfork-events+;vforkdone-events+;binary-upload+;ReverseContinue+;ReverseStep+;QDisableRandomization+;QEnvironmentHexEncoded+;QEnvironmentUnset+;QEnvironmentReset+;QStartupWithShell+;QSetWorkingDir+;swbreak+;hwbreak+;QTBuffer:size+;TracepointSource+;QCatchSyscalls+;qXfer:features:read+;qXfer:memory-map:read+;qXfer:exec-file:read+;qXfer:auxv:read+;qXfer:libraries-svr4:read+;qXfer:libraries:read+#2f
 TRACE gdbstub::protocol::recv_packet     > <-- $QThreadSuffixSupported#e4
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("QThreadSuffixSupported")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $QListThreadsInStopReply#21
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("QListThreadsInStopReply")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qHostInfo#9b
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qHostInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $vCont?#49
 TRACE gdbstub::protocol::response_writer > --> $vCont;c;C;s;S;r#0f
 TRACE gdbstub::protocol::recv_packet     > <-- $qVAttachOrWaitSupported#38
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qVAttachOrWaitSupported")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $QEnableErrorStrings#8c
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("QEnableErrorStrings")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qProcessInfo#dc
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qProcessInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qC#b4
 TRACE gdbstub::protocol::response_writer > --> $QCp01.01#f4
 TRACE gdbstub::protocol::recv_packet     > <-- $qfThreadInfo#bb
 TRACE gdbstub::protocol::response_writer > --> $mp01.01#cd
 TRACE gdbstub::protocol::recv_packet     > <-- $qsThreadInfo#c8
 TRACE gdbstub::protocol::response_writer > --> $l#6c
 TRACE gdbstub::protocol::recv_packet     > <-- $?#3f
 TRACE gdbstub::protocol::response_writer > --> $T05thread:p01.01;#06
 TRACE gdbstub::protocol::recv_packet     > <-- $qProcessInfo#dc
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qProcessInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qProcessInfo#dc
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qProcessInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:features:read:target.xml:0,fff#7d
 TRACE gdbstub::protocol::response_writer > --> $m<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
    <architecture>armv4t</architecture>
    <feature name="org.gnu.gdb.arm.core">
        <vector id="padding" type="uint32" count="25"/>

        <reg name="r0" bitsize="32" type="uint32"/>
        <reg name="r1" bitsize="32" type="uint32"/>
        <reg name="r2" bitsize="32" type="uint32"/>
        <reg name="r3" bitsize="32" type="uint32"/>
        <reg name="r4" bitsize="32" type="uint32"/>
        <reg name="r5" bitsize="32" type="uint32"/>
        <reg name="r6" bitsize="32" type="uint32"/>
        <reg name="r7" bitsize="32" type="uint32"/>
        <reg name="r8" bitsize="32" type="uint32"/>
        <reg name="r9" bitsize="32" type="uint32"/>
        <reg name="r10" bitsize="32" type="uint32"/>
        <reg name="r11" bitsize="32" type="uint32"/>
        <reg name="r12" bitsize="32" type="uint32"/>
        <reg name="sp" bitsize="32" type="data_ptr"/>
        <reg name="lr" bitsize="32"/>
        <reg name="pc" bitsize="32" type="code_ptr"/>

        <!--
            For some reason, my version of `gdb-multiarch` doesn't seem to
            respect "regnum", and will not parse this custom target.xml unless I
            manually include the padding bytes in the target description.

            On the bright side, AFAIK, there aren't all that many architectures
            that use padding bytes. Heck, the only reason armv4t uses padding is
            for historical reasons (see comment below).

            Odds are if you're defining your own custom arch, you won't run into
            this issue, since you can just lay out all the registers in the
            correct order.
        -->
        <reg name="padding" type="padding" bitsize="32"/>

        <!-- The CPSR is register 25, rather than register 16, because
        the FPA registers historically were placed between the PC
        and the CPSR in the "g" packet. -->
        <reg name="cpsr" bitsize="32" regnum="25"/>
    </feature>
    <xi:include href="extra.xml"/>
</target>#08
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:features:read:target.xml:80d,fff#19
 TRACE gdbstub::protocol::response_writer > --> $l#6c
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:features:read:extra.xml:0,fff#1a
 TRACE gdbstub::protocol::response_writer > --> $m<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<feature name="custom-armv4t-extension">
    <!--
        maps to a simple scratch register within the emulator. the GDB
        client can read the register using `p }custom` and set it using
        `set }custom=1337`
    -->
    <reg name="custom" bitsize="32" type="uint32"/>

    <!--
        pseudo-register that return the current time when read.

        notably, i've set up the target to NOT send this register as part of
        the regular register list, which means that GDB will fetch/update
        this register via the 'p' and 'P' packets respectively
    -->
    <reg name="time" bitsize="32" type="uint32"/>

    <!--
        pseudo-register that is always unavailable.

        it is supposed to be reported as 'x'-ed bytes in replies to 'p' packets
        and shown by the GDB client as "<unavailable>".
    -->
    <reg name="unavailable" bitsize="32" type="uint32"/>
</feature>#e9
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:features:read:extra.xml:3c5,fff#b5
 TRACE gdbstub::protocol::response_writer > --> $l#6c
 TRACE gdbstub::protocol::recv_packet     > <-- $Hg1#e0
 TRACE gdbstub::protocol::response_writer > --> $OK#9a
 TRACE gdbstub::protocol::recv_packet     > <-- $p0#a0
 TRACE gdbstub::protocol::response_writer > --> $00000000#dc
 TRACE gdbstub::protocol::recv_packet     > <-- $qProcessInfo#dc
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qProcessInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qProcessInfo#dc
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qProcessInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qProcessInfo#dc
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qProcessInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qStructuredDataPlugins#02
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qStructuredDataPlugins")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qShlibInfoAddr#6a
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qShlibInfoAddr")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:libraries-svr4:read::0,fff#91
 TRACE gdbstub::protocol::response_writer > --> $m<library-list-svr4 version="1.0" main-lm="0x4">
    <library name="/test.elf" lm="0x8" l_addr="0" l_ld="0" lmid="0x14"/>
</library-list-svr4>#25
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:libraries-svr4:read::8d,fff#fd
 TRACE gdbstub::protocol::response_writer > --> $l#6c
 TRACE gdbstub::protocol::recv_packet     > <-- $x0,200#66
 TRACE gdbstub::protocol::response_writer > --> $b#06
 TRACE gdbstub::protocol::recv_packet     > <-- $qfThreadInfo#bb
 TRACE gdbstub::protocol::response_writer > --> $mp01.01#cd
 TRACE gdbstub::protocol::recv_packet     > <-- $qsThreadInfo#c8
 TRACE gdbstub::protocol::response_writer > --> $l#6c
 TRACE gdbstub::protocol::recv_packet     > <-- $pf#d6
 TRACE gdbstub::protocol::response_writer > --> $00005555#f9
 TRACE gdbstub::protocol::recv_packet     > <-- $p19#da
 TRACE gdbstub::protocol::response_writer > --> $10000000#dd
 TRACE gdbstub::protocol::recv_packet     > <-- $jThreadsInfo#c1
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("jThreadsInfo")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qMemoryRegionInfo:55550000#a8
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("qMemoryRegionInfo:55550000")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:memory-map:read::0,fff#1c
 TRACE gdbstub::protocol::response_writer > --> $m<?xml version="1.0"?>
<!DOCTYPE memory-map
    PUBLIC "+//IDN gnu.org//DTD GDB Memory Map V1.0//EN"
            "http://sourceware.org/gdb/gdb-memory-map.dtd">
<memory-map>
    <memory type="ram" start="0x20000000" length="0x20000"/>
    <memory type="flash" start="0x08000000" length="0x10000">
        <property name="blocksize">0x4000</property>
    </memory>
    <memory type="flash" start="0x08010000" length="0x10000">
        <property name="blocksize">0x10000</property>
    </memory>
    <memory type="flash" start="0x08020000" length="0x60000">
        <property name="blocksize">0x20000</property>
    </memory>
</memory-map>#36
 TRACE gdbstub::protocol::recv_packet     > <-- $qXfer:memory-map:read::27c,fff#b8
 TRACE gdbstub::protocol::response_writer > --> $l#6c
 TRACE gdbstub::protocol::recv_packet     > <-- $pb#d2
 TRACE gdbstub::protocol::response_writer > --> $00000000#dc
 TRACE gdbstub::protocol::recv_packet     > <-- $pd#d4
 TRACE gdbstub::protocol::response_writer > --> $00000010#dd
 TRACE gdbstub::protocol::recv_packet     > <-- $jThreadExtendedInfo:#b9
 INFO  gdbstub::stub::core_impl           > Unknown command: Ok("jThreadExtendedInfo:")
 TRACE gdbstub::protocol::response_writer > --> $#00
 TRACE gdbstub::protocol::recv_packet     > <-- $x55550000,200#ca
 TRACE gdbstub::protocol::response_writer > --> $b�-�����M�0�0
                                                              �0��0
                                                                   0�0
                                                                      �0��0
                                                                           �0��
                                                                               0
                                                                                �0�0
                                                                                    �
                                                                                     0��
                                                                                        0
                                                                                         �
                                                                                          0     ����05
 TRACE gdbstub::protocol::recv_packet     > <-- $x5554fe00,200#34
 TRACE gdbstub::protocol::response_writer > --> $b#06
 TRACE gdbstub::protocol::recv_packet     > <-- $x55503000,200#c8
 TRACE gdbstub::protocol::response_writer > --> $b#06
 TRACE gdbstub::protocol::recv_packet     > <-- $x55548000,200#d1
 TRACE gdbstub::protocol::response_writer > --> $b#06
 TRACE gdbstub::protocol::recv_packet     > <-- $x5554f800,200#07
 TRACE gdbstub::protocol::response_writer > --> $b#06
 TRACE gdbstub::protocol::recv_packet     > <-- $x5554fc00,200#32
 TRACE gdbstub::protocol::response_writer > --> $b#06
 TRACE gdbstub::protocol::recv_packet     > <-- $x55550400,200#ce
 TRACE gdbstub::protocol::response_writer > --> $b#06
 TRACE gdbstub::protocol::recv_packet     > <-- $vCont;c:p1.-1#0f
 TRACE gdbstub::stub::state_machine       > transition: "Idle<armv4t::emu::Emu>" --> "Running"

Before/After `./example_no_std/check_size.sh` output

Before

File  .text    Size          Crate Name
2.5%  68.4% 10.3KiB      [Unknown] main
0.2%   6.4%    975B        gdbstub gdbstub::stub::state_machine::GdbStubStateMachineInner<gdbstub::stub::state_machine::state::Running,T,C>::report_stop
0.1%   2.4%    372B        gdbstub gdbstub::protocol::commands::breakpoint::BasicBreakpoint::from_slice
0.1%   1.9%    295B        gdbstub <gdbstub::protocol::common::thread_id::ThreadId as core::convert::TryFrom<&[u8]>>::try_from
0.1%   1.8%    275B        gdbstub gdbstub::protocol::common::hex::decode_hex_buf
0.1%   1.4%    222B        gdbstub gdbstub::stub::core_impl::resume::<impl gdbstub::stub::core_impl::GdbStubImpl<T,C>>::write_stop_common
0.1%   1.4%    221B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write
0.0%   1.3%    204B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_specific_thread_id
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    132B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.9%    131B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.8%    122B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::inner_write
0.0%   0.7%    110B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.7%    109B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    107B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    106B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_addrs
0.0%   0.7%    104B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_hex
0.0%   0.7%    102B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::flush
0.0%   0.6%     93B           core <core::iter::adapters::skip::Skip<I> as core::iter::traits::iterator::Iterator>::next
0.0%   0.6%     92B        gdbstub <gdbstub::protocol::common::thread_id::IdKind as core::convert::TryFrom<&[u8]>>::try_from
0.0%   0.6%     87B           core <core::slice::iter::SplitMut<T,P> as core::iter::traits::iterator::Iterator>::next
0.0%   0.4%     67B   gdbstub_arch <gdbstub_arch::arm::reg::arm_core::ArmCoreRegs as gdbstub::arch::Registers>::gdb_deserialize
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_addrs
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::resume
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::set_resume_action_continue
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::clear_resume_actions
0.0%   0.3%     44B  gdbstub_nostd gdbstub_nostd::print_str::print_str
0.0%   0.2%     38B      [Unknown] _start
0.0%   0.0%      6B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::breakpoints::SwBreakpoint>::add_sw_breakpoint
3.6% 100.0% 15.0KiB                .text section size, the file size is 411.9KiB
target/release/gdbstub-nostd  :
section               size    addr
.interp                 28     680
.note.ABI-tag           32     708
.note.gnu.build-id      36     740
.dynsym                360     776
.gnu.version            30    1136
.gnu.version_r          64    1168
.gnu.hash               28    1232
.dynstr                204    1260
.rela.dyn              408    1464
.rela.plt               24    1872
.rodata                979    1904
.eh_frame_hdr          268    2884
.eh_frame             1328    3152
.text                15338    8576
.init                   27   23916
.fini                   13   23944
.plt                    32   23968
.fini_array              8   28096
.init_array              8   28104
.dynamic               432   28112
.got                   112   28544
.got.plt                32   28656
.relro_padding        4080   28688
.tm_clone_table          0   32784
.data                    8   32784
.bss                     1   32792
.comment               184       0
Total                24064

After

File  .text    Size          Crate Name
2.5%  68.4% 10.3KiB      [Unknown] main
0.2%   6.4%    975B        gdbstub gdbstub::stub::state_machine::GdbStubStateMachineInner<gdbstub::stub::state_machine::state::Running,T,C>::report_stop
0.1%   2.4%    372B        gdbstub gdbstub::protocol::commands::breakpoint::BasicBreakpoint::from_slice
0.1%   1.9%    295B        gdbstub <gdbstub::protocol::common::thread_id::ThreadId as core::convert::TryFrom<&[u8]>>::try_from
0.1%   1.8%    275B        gdbstub gdbstub::protocol::common::hex::decode_hex_buf
0.1%   1.4%    222B        gdbstub gdbstub::stub::core_impl::resume::<impl gdbstub::stub::core_impl::GdbStubImpl<T,C>>::write_stop_common
0.1%   1.4%    221B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write
0.0%   1.3%    204B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_specific_thread_id
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    132B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.9%    131B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.8%    122B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::inner_write
0.0%   0.7%    110B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.7%    109B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    107B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    106B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_addrs
0.0%   0.7%    104B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_hex
0.0%   0.7%    102B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::flush
0.0%   0.6%     93B           core <core::iter::adapters::skip::Skip<I> as core::iter::traits::iterator::Iterator>::next
0.0%   0.6%     92B        gdbstub <gdbstub::protocol::common::thread_id::IdKind as core::convert::TryFrom<&[u8]>>::try_from
0.0%   0.6%     87B           core <core::slice::iter::SplitMut<T,P> as core::iter::traits::iterator::Iterator>::next
0.0%   0.4%     67B   gdbstub_arch <gdbstub_arch::arm::reg::arm_core::ArmCoreRegs as gdbstub::arch::Registers>::gdb_deserialize
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_addrs
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::resume
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::set_resume_action_continue
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::clear_resume_actions
0.0%   0.3%     44B  gdbstub_nostd gdbstub_nostd::print_str::print_str
0.0%   0.2%     38B      [Unknown] _start
0.0%   0.0%      6B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::breakpoints::SwBreakpoint>::add_sw_breakpoint
3.6% 100.0% 15.0KiB                .text section size, the file size is 412.2KiB
target/release/gdbstub-nostd  :
section               size    addr
.interp                 28     680
.note.ABI-tag           32     708
.note.gnu.build-id      36     740
.dynsym                360     776
.gnu.version            30    1136
.gnu.version_r          64    1168
.gnu.hash               28    1232
.dynstr                204    1260
.rela.dyn              408    1464
.rela.plt               24    1872
.rodata                979    1904
.eh_frame_hdr          268    2884
.eh_frame             1328    3152
.text                15338    8576
.init                   27   23916
.fini                   13   23944
.plt                    32   23968
.fini_array              8   28096
.init_array              8   28104
.dynamic               432   28112
.got                   112   28544
.got.plt                32   28656
.relro_padding        4080   28688
.tm_clone_table          0   32784
.data                    8   32784
.bss                     1   32792
.comment               184       0
Total                24064

Copy link
Owner

@daniel5151 daniel5151 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you weren't able to get GDB to use the x packet because you didn't add the necessary qSupported feature negotiation logic. As per the docs - the stub needs to report binary-upload is supported, validate that the client's supported features includes binary-upload, and if the two line up - hook that into gdbstub's protocol feature logic to enable the codepath.

Also, since this is a (relatively?) new packet, you'll want to make sure you're running a (relative?) recent GDB version that supports it.

Of course, if the user has explicitly disable use_x_lowcase_packet in gdbstub, gdbstub should avoid advertising support for binary-upload in qSupported.

Once you do that, re-run validation, and you should hopefully see GDB using the x packet correctly.

@dblnz dblnz force-pushed the feat/add-x-packet-support branch from 6303b47 to 2fb8272 Compare March 8, 2026 18:34
@dblnz
Copy link
Author

dblnz commented Mar 8, 2026

I managed to get this working and I updated the PR and description with the output from a debugging session using lldb (I managed to get this working by compiling lldb from the llvm-project latest main - weirdly enough, the latest released version didn't work).
Let me know what you think about this,

Copy link
Owner

@daniel5151 daniel5151 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's a little bug lurking in the implementation (that shouldn't be hard to fix).

Aside from that, the implementation is looking good to me!

Validation is also looking good, though could you please also include

  • The output from the GDB (or LLDB) session that you used to validate the implementation (so I can confirm both the client and server-side are working properly)
    • particularly useful in this case, given that it might've helped spot the bug in the current impl :)
  • The output of the ./example_no_std/check_size.sh script

crate::__dead_code_marker!("x_lowcase_packet", "impl");

let handler_status = match command {
XLowcasePacket::x(cmd) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: we should be able to share the implementation of this method with the m handler in handle_base, and avoid copy-pasting.

I'll look into this myself after this diff lands, since I want to make sure however we do it, it doesn't result in poor codegen on minimal stubs.

@dblnz
Copy link
Author

dblnz commented Mar 12, 2026

Looks like there's a little bug lurking in the implementation (that shouldn't be hard to fix).

I'm curious what to bug you are referring to. Something to do with the binary output? I had some issues with copy/pasting from my terminal (my tmux and windows terminal don't play well together 😄 ). I'll see how I get that fix before pasting here again

@daniel5151
Copy link
Owner

Looks like there's a little bug lurking in the implementation (that shouldn't be hard to fix).

I'm curious what to bug you are referring to. Something to do with the binary output? I had some issues with copy/pasting from my terminal (my tmux and windows terminal don't play well together 😄 ). I'll see how I get that fix before pasting here again

I'm talking about the extra space. Should be "b", not "b "

#186 (comment)

@dblnz
Copy link
Author

dblnz commented Mar 12, 2026

I'm talking about the extra space. Should be "b", not "b "

#186 (comment)

Oh, I thought it was something else. Thanks! I'll get it fixed

- Add `gdbstub` support for `x` packet that responds with `b`
  prefixed packed to indicate a binary format
- This is by default disabled, implement the `use_x_lowcase_packet`
  method of `Target` to enable it
- When this is enabled, `gdbstub` responds with `binary-upload+` to
  `qSupported` packet, to indicate support of this command.

Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
@dblnz dblnz force-pushed the feat/add-x-packet-support branch from 2fb8272 to 07e340e Compare March 12, 2026 22:07
@dblnz
Copy link
Author

dblnz commented Mar 12, 2026

I updated the description with the output I got from LLDB and ./example_no_std/check_size.sh.
To test this, I modified the armv4t example to enable the x packet, however I haven't included that in the PR.
I am not sure whether I should.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support x packet for binary memory read.

2 participants