-
-
Notifications
You must be signed in to change notification settings - Fork 75
Implement --no-reset mode for live attach to a running device #414
base: main
Are you sure you want to change the base?
Conversation
Read the vector table (instead of looking at current PC/SP).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. I added a few suggestions and questions.
PS. you are allowed to disagree with the suggestions.
@@ -130,7 +130,7 @@ impl Outcome { | |||
Outcome::StackOverflow => log::error!("the program has overflowed its stack"), | |||
Outcome::HardFault => log::error!("the program panicked"), | |||
Outcome::Ok => log::info!("device halted without error"), | |||
Outcome::CtrlC => log::info!("device halted by user"), | |||
Outcome::CtrlC => log::info!("interrupted by user"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outcome::CtrlC => log::info!("interrupted by user"), | |
Outcome::CtrlC => log::info!("device interrupted by user"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to the current message because it's the probe that was interrupted, not the device -- the device keeps running if you do --no-reset
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can actually have two different messages then?
Outcome::CtrlC => log::info!("interrupted by user"), | |
Outcome::CtrlC if opts.no_reset == true => log::info!("interrupted by user; program keeps running"), | |
Outcome::CtrlC if opts.no_reset == false => log::info!("device halted by by user"), |
I am not sure if opts
is in scope here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not, but we can just add it as an argument:
fn log(&self, no_reset: bool)
pub initial_stack_pointer: u32, | ||
// entry 1: Reset vector | ||
pub reset: u32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was some discussion if we can extract the reset vector from the elf or not and how to make this as stable as possible. Please see #383 (comment). Do you think we can always™️ extract the reset vector the way you implemented it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the linked discussion:
It could be that the Flash memory at 0x2000_0000 is aliased at address 0x0000_0000 but I have not checked.
I think that's a typo: the Flash memory is (on STM32s for example; in principe it could be anywhere the instruction fetches are legal) at 0x0800_0000 and the SRAM is (always) at 0x2000_0000.
However, that aside, I looked it up in the ARMv7-M ARM and it seems that I misremembered some details and a much more reliable way would be to read the IVT address from the VTOR register on attach and then use that. I can implement that later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can implement that later.
That would be nice. Maybe in a follow up PR.
In any case I we will need to test the current PR with the rp pico, because that one seems to behave a bit differently than many other microcontrollers because of the bootloader.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do the testing. Just need to set it up.
src/main.rs
Outdated
} | ||
|
||
// run program and print logs until there is an exception | ||
start_program(core, elf)?; | ||
attach_to_program(core, elf)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotta update it here too:
attach_to_program(core, elf)?; | |
attack_the_program(core, elf)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh no 😆 I am sorry. This was meant to be a joke 🙈 Please change it back to attach_to_program
🤣
Co-authored-by: Johann Hemmann <[email protected]>
@whitequark What is the status? 😄 |
@Urhengulas I've been taking care of my health. ETA is this weekend. |
That is very good! 🍀 |
@whitequark friendly ping 🛎️ |
I'm doing way better! I think I'll do this Saturday. |
That's great to hear! |
Sorry, I don't think I'll find time to work on this any time soon as I've not had a chance to use probe-rs in months. Feel free to do with the PR whatever you like. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like some of my responses never went through.
log::debug!("detaching from program"); | ||
|
||
if let Some(rtt_buffer_address) = elf.rtt_buffer_address() { | ||
set_rtt_blocking_mode(core, rtt_buffer_address, false)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah this is true.
set_rtt_blocking_mode(core, rtt_buffer_address, false)?; | ||
} | ||
|
||
core.clear_hw_breakpoint(cortexm::clear_thumb_bit(elf.vector_table.hard_fault).into())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's some code I moved around--I didn't introduce it. For some reason (I didn't investigate closely) probe-run
sets a breakpoint on HardFault. Probably to display a nicer error if you hit one?
|
||
match (core.available_breakpoint_units()?, elf.rtt_buffer_address()) { | ||
(0, Some(_)) => bail!("RTT not supported on device without HW breakpoints"), | ||
(0, None) => log::warn!("device doesn't support HW breakpoints; HardFault will NOT make `probe-run` exit with an error code"), | ||
(_, Some(rtt_buffer_address)) => set_rtt_to_blocking(core, elf.main_fn_address(), rtt_buffer_address)?, | ||
(_, Some(rtt_buffer_address)) => | ||
set_rtt_blocking_mode(core, rtt_buffer_address, true)?, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like #[pre_init]
specifies any access to memory as UB, so it's not really "life before main".
Fixes #354. Includes some related cleanups.
In my testing this works quite well, including backtraces. The one thing I haven't tested is really flooding defmt with messages, but it probably works fine.