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

add qRegisterInfo packet support #103

Merged
merged 1 commit into from Jun 12, 2022

Conversation

jawilk
Copy link
Contributor

@jawilk jawilk commented May 31, 2022

Description

This implements the LLDB specifc qRegisterInfo packet (documentation here).

Relates to #99
I was working on a target where I had some trouble getting the .xml target description formatting right so I opted to use the qRegisterInfo packet instead which pretty much worked right away. I haven't looked into unifying them as mentioned in the compatibility issue as of now though.
One caveat is that some values in the reply need to be in decimal representation. Due to this I added a write_dec() method in the ResponseWriter (I'm not sure this was actually necessary). Since this packet is only used by LLDB it might be reasonable to just hide it behind a feature flag. Besides that, if enabled, the Register struct in gdbstub/src/target/ext/register_info.rs has a few &'static str members which lead to a bigger binary as well.

API Stability

  • This PR does not require a breaking API change

Checklist

  • Implementation
    • cargo build compiles without errors or warnings
    • cargo clippy runs without errors or warnings
    • cargo fmt was run
    • All tests pass
  • Documentation
    • rustdoc + approprate inline code comments
    • Updated CHANGELOG.md
  • If implementing a new protocol extension IDET
    • Included a basic sample implementation in examples/armv4t
      ->Done but might be better to comment it out because it only applies to LLDB
    • Included output of running examples/armv4t with RUST_LOG=trace + any relevant GDB output under the "Validation" section below
      ->attached the LLDB output instead
    • Confirmed that IDET can be optimized away (using ./scripts/test_dead_code_elim.sh and/or ./example_no_std/check_size.sh)
    • OR Implementation requires adding non-optional binary bloat (please elaborate under "Description")
      ->Additional write_dec() method

Validation

LLDB output
(lldb) gdb-remote 9001
lldb-10          <   1> send packet: +
lldb-10          history[1] tid=0x769a <   1> send packet: +
lldb-10          <  19> send packet: $QStartNoAckMode#b0
lldb-10          <   1> read packet: +
lldb-10          <   6> read packet: $OK#9a
lldb-10          <   1> send packet: +
lldb-10          <  45> send packet: $qSupported:xmlRegisters=i386,arm,mips,arc#74
lldb-10          < 333> read packet: $PacketSize=1000;vContSupported+;multiprocess+;QStartNoAckMode+;ReverseContinue+;ReverseStep+;QDisableRandomization+;QEnvironmentHexEncoded+;QEnvironmentUnset+;QEnvironmentReset+;QStartupWithShell+;QSetWorkingDir+;swbreak+;hwbreak+;QCatchSyscalls+;qXfer:features:read+;qXfer:memory-map:read+;qXfer:exec-file:read+;qXfer:auxv:read+#fa
lldb-10          <  26> send packet: $QThreadSuffixSupported#e4
lldb-10          <   4> read packet: $#00
lldb-10          <  27> send packet: $QListThreadsInStopReply#21
lldb-10          <   4> read packet: $#00
lldb-10          <  13> send packet: $qHostInfo#9b
lldb-10          <   4> read packet: $#00
lldb-10          <  10> send packet: $vCont?#49
lldb-10          <  19> read packet: $vCont;c;C;s;S;r#0f
lldb-10          <  27> send packet: $qVAttachOrWaitSupported#38
lldb-10          <   4> read packet: $#00
lldb-10          <  23> send packet: $QEnableErrorStrings#8c
lldb-10          <   4> read packet: $#00
lldb-10          <  16> send packet: $qProcessInfo#dc
lldb-10          <   4> read packet: $#00
lldb-10          <   6> send packet: $qC#b4
lldb-10          <   4> read packet: $#00
lldb-10          <  16> send packet: $qfThreadInfo#bb
lldb-10          <   7> read packet: $m01#ce
lldb-10          <  16> send packet: $qsThreadInfo#c8
lldb-10          <   5> read packet: $l#6c
lldb-10          <   5> send packet: $?#3f
lldb-10          <   7> read packet: $S05#b8
lldb-10          <  16> send packet: $qProcessInfo#dc
lldb-10          <   4> read packet: $#00
lldb-10          <  18> send packet: $qRegisterInfo0#72
lldb-10          < 107> read packet: $name:r0;alt-name:r0;bitsize:32;offset:0;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;#bb
lldb-10          <  18> send packet: $qRegisterInfo1#73
lldb-10          < 107> read packet: $name:r1;alt-name:r1;bitsize:32;offset:4;encoding:uint;format:hex;set:General Purpose Registers;dwarf:1;#c2
lldb-10          <  18> send packet: $qRegisterInfo2#74
lldb-10          < 107> read packet: $name:r2;alt-name:r2;bitsize:32;offset:8;encoding:uint;format:hex;set:General Purpose Registers;dwarf:2;#c9
lldb-10          <  18> send packet: $qRegisterInfo3#75
lldb-10          < 108> read packet: $name:r3;alt-name:r3;bitsize:32;offset:12;encoding:uint;format:hex;set:General Purpose Registers;dwarf:3;#f7
lldb-10          <  18> send packet: $qRegisterInfo4#76
lldb-10          < 108> read packet: $name:r4;alt-name:r4;bitsize:32;offset:16;encoding:uint;format:hex;set:General Purpose Registers;dwarf:4;#fe
lldb-10          <  18> send packet: $qRegisterInfo5#77
lldb-10          < 108> read packet: $name:r5;alt-name:r5;bitsize:32;offset:20;encoding:uint;format:hex;set:General Purpose Registers;dwarf:5;#fc
lldb-10          <  18> send packet: $qRegisterInfo6#78
lldb-10          < 108> read packet: $name:r6;alt-name:r6;bitsize:32;offset:24;encoding:uint;format:hex;set:General Purpose Registers;dwarf:6;#03
lldb-10          <  18> send packet: $qRegisterInfo7#79
lldb-10          < 108> read packet: $name:r7;alt-name:r7;bitsize:32;offset:28;encoding:uint;format:hex;set:General Purpose Registers;dwarf:7;#0a
lldb-10          <  18> send packet: $qRegisterInfo8#7a
lldb-10          < 108> read packet: $name:r8;alt-name:r8;bitsize:32;offset:32;encoding:uint;format:hex;set:General Purpose Registers;dwarf:8;#08
lldb-10          <  18> send packet: $qRegisterInfo9#7b
lldb-10          < 108> read packet: $name:r9;alt-name:r9;bitsize:32;offset:36;encoding:uint;format:hex;set:General Purpose Registers;dwarf:9;#0f
lldb-10          <  18> send packet: $qRegisterInfoa#a3
lldb-10          < 111> read packet: $name:r10;alt-name:r10;bitsize:32;offset:40;encoding:uint;format:hex;set:General Purpose Registers;dwarf:10;#82
lldb-10          <  18> send packet: $qRegisterInfob#a4
lldb-10          < 111> read packet: $name:r11;alt-name:r11;bitsize:32;offset:44;encoding:uint;format:hex;set:General Purpose Registers;dwarf:11;#89
lldb-10          <  18> send packet: $qRegisterInfoc#a5
lldb-10          < 111> read packet: $name:r12;alt-name:r12;bitsize:32;offset:48;encoding:uint;format:hex;set:General Purpose Registers;dwarf:12;#90
lldb-10          <  18> send packet: $qRegisterInfod#a6
lldb-10          < 120> read packet: $name:sp;alt-name:sp;bitsize:32;offset:52;encoding:uint;format:hex;set:General Purpose Registers;dwarf:13;generic:sp;#dd
lldb-10          <  18> send packet: $qRegisterInfoe#a7
lldb-10          < 109> read packet: $name:lr;alt-name:lr;bitsize:32;offset:56;encoding:uint;format:hex;set:General Purpose Registers;dwarf:14;#a3
lldb-10          <  18> send packet: $qRegisterInfof#a8
lldb-10          < 120> read packet: $name:pc;alt-name:pc;bitsize:32;offset:60;encoding:uint;format:hex;set:General Purpose Registers;dwarf:15;generic:pc;#ae
lldb-10          <  19> send packet: $qRegisterInfo10#a3
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:64;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:16;#6e
lldb-10          <  19> send packet: $qRegisterInfo11#a4
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:68;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:17;#73
lldb-10          <  19> send packet: $qRegisterInfo12#a5
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:72;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:18;#6f
lldb-10          <  19> send packet: $qRegisterInfo13#a6
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:76;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:19;#74
lldb-10          <  19> send packet: $qRegisterInfo14#a7
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:80;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:20;#67
lldb-10          <  19> send packet: $qRegisterInfo15#a8
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:84;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:21;#6c
lldb-10          <  19> send packet: $qRegisterInfo16#a9
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:88;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:22;#71
lldb-10          <  19> send packet: $qRegisterInfo17#aa
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:92;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:23;#6d
lldb-10          <  19> send packet: $qRegisterInfo18#ab
lldb-10          < 129> read packet: $name:padding;alt-name:padding;bitsize:32;offset:96;encoding:vector;format:vector-uint8;set:Floating Point Registers;dwarf:24;#72
lldb-10          <  19> send packet: $qRegisterInfo19#ac
lldb-10          < 114> read packet: $name:cpsr;alt-name:cpsr;bitsize:32;offset:100;encoding:uint;format:hex;set:General Purpose Registers;dwarf:25;#7f
lldb-10          <  19> send packet: $qRegisterInfo1a#d4
lldb-10          <   7> read packet: $E45#ae
lldb-10          <  16> send packet: $qfThreadInfo#bb
lldb-10          <   7> read packet: $m01#ce
lldb-10          <  16> send packet: $qsThreadInfo#c8
lldb-10          <   5> read packet: $l#6c
lldb-10          <   7> send packet: $Hg1#e0
lldb-10          <   6> read packet: $OK#9a
lldb-10          <   6> send packet: $p0#a0
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <  16> send packet: $qProcessInfo#dc
lldb-10          <   4> read packet: $#00
lldb-10          <  26> send packet: $qStructuredDataPlugins#02
lldb-10          <   4> read packet: $#00
lldb-10          <  13> send packet: $qSymbol::#5b
lldb-10          <   4> read packet: $#00
lldb-10          <  16> send packet: $qfThreadInfo#bb
lldb-10          <   7> read packet: $m01#ce
lldb-10          <  16> send packet: $qsThreadInfo#c8
lldb-10          <   5> read packet: $l#6c
lldb-10          <  16> send packet: $qfThreadInfo#bb
lldb-10          <   7> read packet: $m01#ce
lldb-10          <  16> send packet: $qsThreadInfo#c8
lldb-10          <   5> read packet: $l#6c
lldb-10          <   6> send packet: $pf#d6
lldb-10          <  10> read packet: $0* 5* #f9
lldb-10          <   7> send packet: $p19#da
lldb-10          <  10> read packet: $1000*!#0c
lldb-10          <   6> send packet: $pd#d4
lldb-10          <  10> read packet: $00*!10#0c
lldb-10          <   6> send packet: $pe#d5
lldb-10          <  12> read packet: $78563412#a4
lldb-10          <  30> send packet: $qMemoryRegionInfo:12345678#b8
lldb-10          <   4> read packet: $#00
lldb-10          <   6> send packet: $pb#d2
lldb-10          <   7> read packet: $0*$#7e
dbg.evt-handler  <  16> send packet: $jThreadsInfo#c1
(lldb) dbg.evt-handler  <   4> read packet: $#00
dbg.evt-handler  <  24> send packet: $jThreadExtendedInfo:#b9
dbg.evt-handler  <   4> read packet: $#00
Process 1 stopped
* thread #1, stop reason = signal SIGTRAP
    frame #0: 0x55550000 test.elf`main at test.c:1:12
-> 1   	int main() {
   2   	    int x = 4;
   3   	    int y = 3;
   4
   5   	    x += 1;
   6   	    y += 3;
   7
(lldb) register read
lldb-10          <   6> send packet: $p0#a0
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p1#a1
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p2#a2
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p3#a3
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p4#a4
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p5#a5
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p6#a6
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p7#a7
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p8#a8
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $p9#a9
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $pa#d1
lldb-10          <   7> read packet: $0*$#7e
lldb-10          <   6> send packet: $pc#d3
lldb-10          <   7> read packet: $0*$#7e
General Purpose Registers:
        r0 = 0x00000000
        r1 = 0x00000000
        r2 = 0x00000000
        r3 = 0x00000000
        r4 = 0x00000000
        r5 = 0x00000000
        r6 = 0x00000000
        r7 = 0x00000000
        r8 = 0x00000000
        r9 = 0x00000000
       r10 = 0x00000000
       r11 = 0x00000000
       r12 = 0x00000000
        sp = 0x10000000
        lr = 0x12345678
        pc = 0x55550000  test.elf`main at test.c:1:12
      cpsr = 0x00000010

@daniel5151
Copy link
Owner

Hey there, thanks for sending this in!

I'm actually on vacation right now, so I won't get the chance to give this a thorough review until sometime next week. In the meantime, I'll check in occasionally to approve CI runs, since the first and most obvious thing you'll need to fix is that the code within gdbstub must be no_std (i.e: no using Vec).

I would suggest using the ./example_no_std/check_size.sh script to ensure the code is no_std compatible, and also make sure that the implementation doesn't introduce exorbitant binary size overhead on non-lldb implementations.

@jawilk
Copy link
Contributor Author

jawilk commented Jun 1, 2022

Thanks for the quick reply and apologies for disturbing your vacation with this :D

Looks like I lost the view of the bigger picture somehow, it should be no_std now.
The write_dec() method is weighting in with

File  .text    Size             Crate Name
0.0%   0.7%    131B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_dec

compared to the existing ones

0.1%   1.2%    207B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write
0.0%   0.7%    130B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::inner_write
0.0%   0.6%    115B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::flush
0.0%   0.5%     88B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_hex
0.0%   0.6%    104B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
cargo bloat output
File  .text    Size             Crate Name
3.7%  72.2% 12.7KiB         [Unknown] main
0.2%   4.4%    797B           gdbstub gdbstub::stub::state_machine::GdbStubStateMachineInner<gdbstub::stub::state_machine::state::Running,T,C>::report_stop
0.1%   2.0%    366B           gdbstub gdbstub::protocol::commands::breakpoint::BasicBreakpoint::from_slice
0.1%   1.6%    295B    gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::register_info::RegisterInfo>::get_register_info
0.1%   1.5%    268B           gdbstub gdbstub::protocol::common::hex::decode_hex_buf
0.1%   1.4%    253B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_specific_thread_id
0.1%   1.4%    249B           gdbstub gdbstub::stub::core_impl::resume::<impl gdbstub::stub::core_impl::GdbStubImpl<T,C>>::write_stop_common
0.1%   1.3%    232B           gdbstub <gdbstub::protocol::common::thread_id::ThreadId as core::convert::TryFrom<&[u8]>>::try_from
0.1%   1.2%    207B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write
0.0%   0.7%    133B           gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.7%    133B           gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.7%    131B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_dec
0.0%   0.7%    130B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::inner_write
0.0%   0.6%    115B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::flush
0.0%   0.6%    114B           gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.6%    108B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.6%    104B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.6%    103B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.6%    102B    gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_addrs
0.0%   0.6%    101B         [Unknown] __libc_csu_init
0.0%   0.5%     92B           gdbstub <usize as gdbstub::internal::be_bytes::BeBytes>::from_be_bytes
0.0%   0.5%     90B           gdbstub <u32 as gdbstub::internal::be_bytes::BeBytes>::from_be_bytes
0.0%   0.5%     88B           gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_hex
0.0%   0.4%     70B           gdbstub <gdbstub::protocol::common::thread_id::IdKind as core::convert::TryFrom<&[u8]>>::try_from
0.0%   0.4%     65B      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_addrs
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.3%     57B compiler_builtins __rust_probestack
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%     50B    gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::resume
0.0%   0.2%     43B         [Unknown] _start
0.0%   0.0%      6B    gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::breakpoints::SwBreakpoint>::remove_sw_breakpoint
0.0%   0.0%      6B    gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::breakpoints::SwBreakpoint>::add_sw_breakpoint
0.0%   0.0%      2B         [Unknown] __libc_csu_fini
0.0%   0.0%      0B                   And 0 smaller methods. Use -n N to show more.
5.2% 100.0% 17.6KiB                   .text section size, the file size is 339.5KiB
target/release/gdbstub-nostd  :
section               size      addr
.interp                 28       568
.note.ABI-tag           32       596
.note.gnu.build-id      36       628
.gnu.hash               28       664
.dynsym                360       696
.dynstr                193      1056
.gnu.version            30      1250
.gnu.version_r          48      1280
.rela.dyn             1032      1328
.init                   23      2360
.plt                    16      2384
.plt.got                 8      2400
.text                17986      2416
.fini                    9     20404
.rodata               1130     20416
.eh_frame_hdr          316     21548
.eh_frame             1616     21864
.init_array              8   2120712
.fini_array              8   2120720
.data.rel.ro           416   2120728
.dynamic               448   2121144
.got                   136   2121592
.data                    8   2121728
.bss                     8   2121736
.comment                41         0
Total                23964

@daniel5151
Copy link
Owner

Oh, no need to be sorry! gdbstub is my side-project after all, so I'm always happy to chip away at it on my free time :)

I'm about to head back on the road, but I thought I'd throw two more comments your way while I had the chance:

  • For the write_dec helper, can you please use generics to support any integer width, akin to the write_num method?
  • gdbstub has thusfar managed to avoid introducing any artificial limits in its API, so we'll have to workshop some of your proposed design. Namely, you seem to have swapped out your use of Vec with fixed-size arrays with an (as far as I can tell) arbitrarily chosen size. We'll have to reconsider that design. One idea would be to "invert" the API so that instead of returning a Register struct, you could instead pass the handler a &mut dyn FnOnce(Register<'_>), and swap all those fixed-size arrays and &'static strings in Register to use references. i.e:
struct Register<'a> {
    pub name: &'a str, // added benefit: no need to be limited to just &'static str
    pub invalidate_regs: Option<&'a [u16]>, // can be any size
    ...
}

// and then in the handler
fn get_register_info(&mut self, reg_id: u8, cb: &mut dyn FnOnce(Option<Register<'_>>)) -> Result<(), Self::Error> {
    let dynamic_name = String::from("foo");
    let dynamic_regs = vec![1, 2, 3];
    let reg = Register {
        name: &dynamic_name,
        invalidate_regs: &dynamic_regs,
        ...
    };
    (cb)(reg);
    Ok(())
}

i.e: you've lifted the decision of how to / how much to allocate into the handler, rather than imposing that decision onto the user.

If you poke around the codebase, there should be examples of this pattern being used. e.g: this is similar to how the gdb_de/serialize functions work.

@jawilk jawilk force-pushed the qregisterinfo-packet branch 2 times, most recently from dac328a to 84c53df Compare June 2, 2022 15:12
@jawilk
Copy link
Contributor Author

jawilk commented Jun 2, 2022

Thanks a lot again for taking the time, your explanations and pointers were very helpful!

  • write_dec is using generics now
  • I switched to a callback function in get_register_info, but the only way I could make it work was to wrap the callback into a Box Box<dyn FnOnce(Option<Register<'_>>) + '_> which fails for non_std. I need to think a bit more about that.

Regarding changes to the current code, I changed the lifetime of the s argument in write_str to use an anonymous lifetime instead of a static one

pub fn write_str(&mut self, s: &'_ str) -> Result<(), Error<C::Error>> {

@daniel5151
Copy link
Owner

Ah, yes, as for FnOnce, things get a bit complicated, since it needs to take self when invoked, and you can't really do that (in safe Rust) with a stack allocated closure...

Fortunately, this situation is similar to one we encountered while working on Host IO support, and though we didn't end up using a callback for that API, I have a feeling using a callback in this API is a good idea.

Please check out this comment for a proposed API: #66 (comment)
The linked Rust Playground gist is pretty much what you'd want to implement here. i.e: instead of using a bare &mut dyn FnMut(..), you'd wrap that callback in a struct that provides a method that forwards to that implementation, while also consuming self in the process + returning a ZST "token" that must be returned from the handler, thereby guaranteeing that the function has been called.

If you can pull that off, that should get the CI green.

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.

Found some time tonight to give the code a proper comb-over. Left a bunch of comments. Overall, things are looking good!

CHANGELOG.md Outdated Show resolved Hide resolved
examples/armv4t/gdb/register_info.rs Outdated Show resolved Hide resolved
src/protocol/commands/_qRegisterInfo.rs Outdated Show resolved Hide resolved
src/protocol/response_writer.rs Outdated Show resolved Hide resolved
src/protocol/response_writer.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/mod.rs Outdated Show resolved Hide resolved
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.

Some more comments...

Also, on a broader note: I think this new way of reporting registers should also become an (optional) part of the Arch trait, akin to how target.xml is handled today. Of course, you'll have to implement it in such a way that if neither the Arch not the Target provide an implementation, the code still gets dead code eliminated...

If you can take a crack at that, that'd be much appreciated. If not, I can take a hand at helping out with that sometime next week.

src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
src/target/ext/register_info.rs Outdated Show resolved Hide resolved
@jawilk
Copy link
Contributor Author

jawilk commented Jun 5, 2022

If you can take a crack at that, that'd be much appreciated. If not, I can take a hand at helping out with that sometime next week.

I'll give it a try tomorrow! I was actually planning to try upstream the Berkeley Packet Filter (BPF) arch so getting a better sense on that side of things is a good idea

src/target/mod.rs Outdated Show resolved Hide resolved
@daniel5151
Copy link
Owner

If you can take a crack at that, that'd be much appreciated. If not, I can take a hand at helping out with that sometime next week.

I'll give it a try tomorrow! I was actually planning to try upstream the Berkeley Packet Filter (BPF) arch so getting a better sense on that side of things is a good idea

Oh, awesome! Always happy to see more Arch implementations get upstreamed.
Of course, as a reminder, we'd want to land that as a separate PR, in case you were thinking of lumping it in with this one :)

As for the implementation: you'll probably want to mirror how target.xml is being handled:

  • Add a method akin to Target::use_target_description_xml, which can be used to globally enable/disable the use of this functionality
  • Add a new method to Arch, except instead of returning a bare CallbackToken, have it return a Option<CallbackToken>, where the default implementation returns None
  • Within gdbstub, keep a close eye on ensuring that dead-code-elimination still kicks in when neither the Arch nor the Target provide an implementation of this handler (or the aforementioned global enable/disable use_ method is set to false)

If you can't seem to get things working, just let me know. gdbstub has some pretty unique constraints compared to typical Rust projects, so I'm more than happy to do some hands on work to get this PR landed!

@jawilk
Copy link
Contributor Author

jawilk commented Jun 6, 2022

Seems like 24 => Self::Fps, is missing here

let reg = match id {
0..=12 => Self::Gpr(id as u8),
13 => Self::Sp,
14 => Self::Lr,
15 => Self::Pc,
16..=23 => Self::Fpr((id as u8) - 16),
25 => Self::Cpsr,
_ => return None,
};

@jawilk jawilk closed this Jun 6, 2022
@jawilk jawilk reopened this Jun 6, 2022
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.

So, when I said that you should implement this at the Arch level, I'd meant that in addition to the dynamic Target-level implementation 😅

Please re-add the dynamic override implementation, as it is useful for implementations that are generic across multiple architectures.

i.e: there should be 3 "knobs" for specifying qRegisterInfo data:

  • the top-level use_register_info override, that enables completely disabling the packet (regardless of whether the Arch or Target includes implementations of it)
  • The Arch level static Register information
  • The Target level dynamic "override" Register information

Like I said - look at how target.xml is being handled, and match that logic, fallbacks + overrides and all.

examples/armv4t/gdb/mod.rs Outdated Show resolved Hide resolved
examples/armv4t/gdb/mod.rs Outdated Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
src/target/mod.rs Outdated Show resolved Hide resolved
src/target/mod.rs Outdated Show resolved Hide resolved
src/target/mod.rs Outdated Show resolved Hide resolved
@daniel5151
Copy link
Owner

Seems like 24 => Self::Fps, is missing here

huh, would you look at that 👀

I'll try and remember to push up a hotfix right to master at some point

@thefaxman thefaxman mentioned this pull request Jun 8, 2022
11 tasks
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.

mostly doc and style nits, with one somewhat pertinent question regarding possible binary overhead changes...

thanks for bearing with me through all these review cycles, I think we are almost done :)

examples/armv4t/gdb/mod.rs Show resolved Hide resolved
examples/armv4t/gdb/register_info_override.rs Show resolved Hide resolved
examples/armv4t/gdb/register_info_override.rs Outdated Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
src/target/ext/register_info_override.rs Outdated Show resolved Hide resolved
src/target/ext/register_info_override.rs Outdated Show resolved Hide resolved
src/target/ext/register_info_override.rs Outdated Show resolved Hide resolved
src/stub/core_impl/register_info.rs Show resolved Hide resolved
src/arch.rs Outdated Show resolved Hide resolved
@jawilk
Copy link
Contributor Author

jawilk commented Jun 8, 2022

mostly doc and style nits, with one somewhat pertinent question regarding possible binary overhead changes...

thanks for bearing with me through all these review cycles, I think we are almost done :)

Awesome I'll try fixing these now. Thanks for being so patient and the hand holding with very helpful code snippets 😄

@daniel5151
Copy link
Owner

@jawilk, #106 introduced a couple of merge conflicts

@jawilk
Copy link
Contributor Author

jawilk commented Jun 8, 2022

@jawilk, #106 introduced a couple of merge conflicts

done

@daniel5151
Copy link
Owner

Hey, quick update - I've been surprisingly busy lately, so I'll probably get a chance to look at this again sometime this weekend. Sorry about that!

@jawilk
Copy link
Contributor Author

jawilk commented Jun 10, 2022

Hey, quick update - I've been surprisingly busy lately, so I'll probably get a chance to look at this again sometime this weekend. Sorry about that!

no worries, thanks for the update!

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.

Only thing left are some minor comment formatting issues, but honestly, I'll just take care of those myself, since I'll be making some misc. commits prior to releasing 0.6.2 anyways...

Thanks again for the PR!

I'll try and push out 0.6.2 sometime in the next few days :)

Comment on lines +174 to +178
///1. Use the target definition python file if one is specified.
///2. If the target definition doesn't have any of the info from the
///target.xml (registers) then proceed to read the `target.xml`.
///3. Fall back on the `qRegisterInfo` packets.
///4. Use hardcoded defaults if available.
Copy link
Owner

Choose a reason for hiding this comment

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

nit: formatting

Suggested change
///1. Use the target definition python file if one is specified.
///2. If the target definition doesn't have any of the info from the
///target.xml (registers) then proceed to read the `target.xml`.
///3. Fall back on the `qRegisterInfo` packets.
///4. Use hardcoded defaults if available.
/// 1. Use the target definition python file if one is specified.
/// 2. If the target definition doesn't have any of the info from the
/// target.xml (registers) then proceed to read the `target.xml`.
/// 3. Fall back on the `qRegisterInfo` packets.
/// 4. Use hardcoded defaults if available.

/// runtime-configurable target, it's unlikely that you'll need to implement
/// this extension.
pub trait RegisterInfoOverride: Target {
/// Invoke `reg_info.write(reg)` where `reg` is a [`Register`
Copy link
Owner

Choose a reason for hiding this comment

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

nit: weird little formatting issue. reminds you why wrap_comment is still a nightly feature :)

@daniel5151 daniel5151 merged commit 9b6fd55 into daniel5151:master Jun 12, 2022
@daniel5151
Copy link
Owner

Oh, also, heads up: in 4a8f325, I renamed all instances of register_info to lldb_register_info, to make it super extra clear that this is a LLDB specific extension, and if you only care about gdb, you don't need to implement it.

@jawilk jawilk deleted the qregisterinfo-packet branch June 12, 2022 09:30
@daniel5151
Copy link
Owner

@jawilk 0.6.2 has been released :)

@daniel5151
Copy link
Owner

...oh, and thanks for the Coffee!

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.

None yet

2 participants