From f285238164ca3b9f83711d7e3261b19cb0f4f580 Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 21 Jun 2023 00:00:33 +0000 Subject: [PATCH 1/6] backtrace: enhance debug logging for failure cases. --- src/backtrace/unwind.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/backtrace/unwind.rs b/src/backtrace/unwind.rs index b209c8b..4382d69 100644 --- a/src/backtrace/unwind.rs +++ b/src/backtrace/unwind.rs @@ -103,6 +103,15 @@ pub fn target(core: &mut Core, elf: &Elf, target_info: &TargetInfo) -> Output { // the stack was not corrupted. let reset_fn_range = elf.reset_fn_range(); output.corrupted = !(reset_fn_range.contains(&pc) || reset_fn_range.is_empty()); + if output.corrupted { + log::debug!( + "Frame (PC {:#010x}) is not within reset vector ({:#010x}..{:#010x}) \ + and links to itself, the stack is corrupted", + pc, + reset_fn_range.start, + reset_fn_range.end + ); + } break; } @@ -125,6 +134,7 @@ pub fn target(core: &mut Core, elf: &Elf, target_info: &TargetInfo) -> Output { { stacked } else { + log::debug!("Unreadable stacked exception registers, the stack is corrupted"); output.corrupted = true; break; }; @@ -143,9 +153,14 @@ pub fn target(core: &mut Core, elf: &Elf, target_info: &TargetInfo) -> Output { break; } - // if the SP is above the start of the stack, the stack is corrupt match registers.get(registers::SP) { Ok(advanced_sp) if advanced_sp > target_info.stack_start => { + log::debug!( + "SP ({:#010x}) above start of the stack ({:#010x}), the stack \ + is corrupted", + advanced_sp, + target_info.stack_start + ); output.corrupted = true; break; } From 8e718ef9517dc38266e4436698cccf623c6cd9dc Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 21 Jun 2023 00:09:53 +0000 Subject: [PATCH 2/6] Make analyze_vector_table() do what it says on the tin. Read the vector table (instead of looking at current PC/SP). --- src/main.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index dc276ae..c0dfc2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,12 +34,7 @@ use probe_rs::{ }; use signal_hook::consts::signal; -use crate::{ - canary::Canary, - elf::Elf, - registers::{PC, SP}, - target_info::TargetInfo, -}; +use crate::{canary::Canary, elf::Elf, target_info::TargetInfo}; const TIMEOUT: Duration = Duration::from_secs(1); @@ -208,9 +203,9 @@ fn flashing_progress() -> flashing::FlashProgress { /// /// Returns `(stack_start: u32, reset_fn_address: u32)` fn analyze_vector_table(core: &mut Core) -> anyhow::Result<(u32, u32)> { - let stack_start = core.read_core_reg::(SP)?; - let reset_address = cortexm::set_thumb_bit(core.read_core_reg::(PC)?); - Ok((stack_start, reset_address)) + let mut ivt = [0; 2]; + core.read_32(0, &mut ivt[..])?; + Ok((ivt[0], ivt[1])) } fn start_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { From f01365b7b7970d9ac52b9262a566367aee591df6 Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 21 Jun 2023 00:22:33 +0000 Subject: [PATCH 3/6] Remove analyze_vector_table() as the ELF file has that information. --- src/cortexm.rs | 4 +++- src/elf.rs | 11 ++++------- src/main.rs | 16 ++-------------- src/target_info.rs | 3 +-- 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/cortexm.rs b/src/cortexm.rs index 2cb2d51..8d27c11 100644 --- a/src/cortexm.rs +++ b/src/cortexm.rs @@ -46,8 +46,10 @@ pub fn subroutine_eq(addr1: u32, addr2: u32) -> bool { /// The contents of the vector table #[derive(Debug)] pub struct VectorTable { - // entry 0 + // entry 0: Initial SP pub initial_stack_pointer: u32, + // entry 1: Reset vector + pub reset: u32, // entry 3: HardFault handler pub hard_fault: u32, } diff --git a/src/elf.rs b/src/elf.rs index 10c1452..595236f 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -27,11 +27,7 @@ pub struct Elf<'file> { } impl<'file> Elf<'file> { - pub fn parse( - elf_bytes: &'file [u8], - elf_path: &'file Path, - reset_fn_address: u32, - ) -> Result { + pub fn parse(elf_bytes: &'file [u8], elf_path: &'file Path) -> Result { let elf = ObjectFile::parse(elf_bytes)?; let live_functions = extract_live_functions(&elf)?; @@ -42,7 +38,7 @@ impl<'file> Elf<'file> { let debug_frame = extract_debug_frame(&elf)?; - let symbols = extract_symbols(&elf, reset_fn_address)?; + let symbols = extract_symbols(&elf, vector_table.reset)?; Ok(Self { elf, @@ -149,11 +145,12 @@ fn extract_vector_table(elf: &ObjectFile) -> anyhow::Result any core.reset_and_halt(TIMEOUT)?; // gather information - let (stack_start, reset_fn_address) = analyze_vector_table(core)?; let elf_bytes = fs::read(elf_path)?; - let elf = &Elf::parse(&elf_bytes, elf_path, reset_fn_address)?; - let target_info = TargetInfo::new(elf, memory_map, probe_target, stack_start)?; + let elf = &Elf::parse(&elf_bytes, elf_path)?; + let target_info = TargetInfo::new(elf, memory_map, probe_target)?; // install stack canary let canary = Canary::install(core, &target_info, elf, opts.measure_stack)?; @@ -197,17 +196,6 @@ fn flashing_progress() -> flashing::FlashProgress { }) } -/// Read stack-pointer and reset-handler-address from the vector table. -/// -/// Assumes that the target was reset-halted. -/// -/// Returns `(stack_start: u32, reset_fn_address: u32)` -fn analyze_vector_table(core: &mut Core) -> anyhow::Result<(u32, u32)> { - let mut ivt = [0; 2]; - core.read_32(0, &mut ivt[..])?; - Ok((ivt[0], ivt[1])) -} - fn start_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { log::debug!("starting device"); diff --git a/src/target_info.rs b/src/target_info.rs index 9a00a12..a4d245e 100644 --- a/src/target_info.rs +++ b/src/target_info.rs @@ -33,7 +33,6 @@ impl TargetInfo { elf: &Elf, memory_map: Vec, probe_target: probe_rs::Target, - stack_start: u32, ) -> anyhow::Result { let active_ram_region = extract_active_ram_region(&probe_target, elf.vector_table.initial_stack_pointer); @@ -46,7 +45,7 @@ impl TargetInfo { memory_map, probe_target, stack_info, - stack_start, + stack_start: elf.vector_table.initial_stack_pointer, }) } } From 39a470b4a955f507f7f92740ab3b28d71b458bda Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 21 Jun 2023 00:12:09 +0000 Subject: [PATCH 4/6] Implement --no-reset mode for live attach to a running device. --- CHANGELOG.md | 1 + src/backtrace/mod.rs | 2 +- src/cli.rs | 6 ++- src/elf.rs | 9 ----- src/main.rs | 96 +++++++++++++++++++++++++++++++------------- 5 files changed, 75 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d82a82..a60e884 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +- [#414] Add `--no-reset` to attach to/detach from live target - [#405] Also enable merge queue for changelog enforcer - [#404] Switch from bors to merge queue - [#402] Do not panic if locations do not contain the frame diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index 1a1ee2c..b3b20ec 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -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"), } } } diff --git a/src/cli.rs b/src/cli.rs index dadece1..71d358b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -60,7 +60,7 @@ pub struct Opts { list_probes: bool, /// Whether to measure the program's stack consumption. - #[arg(long)] + #[arg(long, conflicts_with = "no-reset")] pub measure_stack: bool, /// Skip writing the application binary to flash. @@ -75,6 +75,10 @@ pub struct Opts { #[arg(long, env = "PROBE_RUN_PROBE")] pub probe: Option, + /// Whether to reset the target when attaching and detaching. Implies `--no-flash`. + #[arg(long = "no-reset", default_value = "true", action = ArgAction::SetFalse)] + pub reset: bool, + /// Whether to shorten paths (e.g. to crates.io dependencies) in backtraces and defmt logs #[arg(long)] pub shorten_paths: bool, diff --git a/src/elf.rs b/src/elf.rs index 595236f..91bae7a 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -52,10 +52,6 @@ impl<'file> Elf<'file> { }) } - pub fn main_fn_address(&self) -> u32 { - self.symbols.main_fn_address - } - pub fn program_uses_heap(&self) -> bool { self.symbols.program_uses_heap } @@ -176,14 +172,12 @@ fn extract_debug_frame<'file>(elf: &ObjectFile<'file>) -> anyhow::Result, rtt_buffer_address: Option, } fn extract_symbols(elf: &ObjectFile, reset_fn_address: u32) -> anyhow::Result { - let mut main_fn_address = None; let mut program_uses_heap = false; let mut reset_symbols = Vec::new(); let mut rtt_buffer_address = None; @@ -196,7 +190,6 @@ fn extract_symbols(elf: &ObjectFile, reset_fn_address: u32) -> anyhow::Result main_fn_address = Some(cortexm::clear_thumb_bit(address)), "_SEGGER_RTT" => rtt_buffer_address = Some(address), "__rust_alloc" | "__rg_alloc" | "__rdl_alloc" | "malloc" if !program_uses_heap => { log::debug!("symbol `{}` indicates heap is in use", name); @@ -211,7 +204,6 @@ fn extract_symbols(elf: &ObjectFile, reset_fn_address: u32) -> anyhow::Result anyhow::Result any // connect to probe and flash firmware let probe_target = lookup_probe_target(elf_path, chip_name, opts)?; let mut sess = attach_to_probe(probe_target.clone(), opts)?; - flash(&mut sess, elf_path, opts)?; + if opts.reset { + flash(&mut sess, elf_path, opts)?; + } - // attack to core + // attach to core let memory_map = sess.target().memory_map.clone(); let core = &mut sess.core(0)?; - // reset-halt the core; this is necessary for analyzing the vector table and - // painting the stack - core.reset_and_halt(TIMEOUT)?; + // reset if requested, and then halt the core; this is necessary for analyzing + // the vector table and painting the stack + if opts.reset { + core.reset_and_halt(TIMEOUT)?; + } else { + core.halt(TIMEOUT)?; + } // gather information let elf_bytes = fs::read(elf_path)?; let elf = &Elf::parse(&elf_bytes, elf_path)?; let target_info = TargetInfo::new(elf, memory_map, probe_target)?; - // install stack canary - let canary = Canary::install(core, &target_info, elf, opts.measure_stack)?; - if opts.measure_stack && canary.is_none() { - bail!("failed to set up stack measurement"); + let canary; + if opts.reset { + // install stack canary + canary = Canary::install(core, &target_info, elf, opts.measure_stack)?; + if opts.measure_stack && canary.is_none() { + bail!("failed to set up stack measurement"); + } + } else { + // cannot safely touch the stack of a running application + canary = None; + log::warn!("You are using `--no-reset` -- stack overflow checks will not be done") } // run program and print logs until there is an exception - start_program(core, elf)?; + attach_to_program(core, elf)?; let current_dir = &env::current_dir()?; let halted_due_to_signal = print_logs(core, current_dir, elf, &target_info.memory_map, opts)?; // blocks until exception print_separator()?; @@ -87,8 +100,13 @@ fn run_target_program(elf_path: &Path, chip_name: &str, opts: &cli::Opts) -> any backtrace::Settings::new(canary_touched, current_dir, halted_due_to_signal, opts); let outcome = backtrace::print(core, elf, &target_info, &mut backtrace_settings)?; - // reset the target - core.reset_and_halt(TIMEOUT)?; + if opts.reset { + // reset the target + core.reset_and_halt(TIMEOUT)?; + } else { + // remove our instrumentation and restart the target + detach_from_program(core, elf)?; + } outcome.log(); Ok(outcome.into()) @@ -196,13 +214,14 @@ fn flashing_progress() -> flashing::FlashProgress { }) } -fn start_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { - log::debug!("starting device"); +fn attach_to_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { + log::debug!("attaching to program"); 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)?, (_, None) => {} } @@ -212,16 +231,33 @@ fn start_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { Ok(()) } +fn detach_from_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { + log::debug!("detaching from program"); + + if let Some(rtt_buffer_address) = elf.rtt_buffer_address() { + set_rtt_blocking_mode(core, rtt_buffer_address, false)?; + } + + core.clear_hw_breakpoint(cortexm::clear_thumb_bit(elf.vector_table.hard_fault).into())?; + core.run()?; + + Ok(()) +} + /// Set rtt to blocking mode -fn set_rtt_to_blocking( +fn set_rtt_blocking_mode( core: &mut Core, - main_fn_address: u32, rtt_buffer_address: u32, + is_blocking: bool, ) -> anyhow::Result<()> { - // set and wait for a hardware breakpoint at the beginning of `fn main()` - core.set_hw_breakpoint(main_fn_address.into())?; - core.run()?; - core.wait_for_core_halted(Duration::from_secs(5))?; + log::debug!( + "setting RTT mode to {}", + if is_blocking { + "blocking" + } else { + "nonblocking" + } + ); // calculate address of up-channel-flags inside the rtt control block const OFFSET: u32 = 44; @@ -232,14 +268,17 @@ fn set_rtt_to_blocking( core.read_32(rtt_buffer_address.into(), channel_flags)?; // modify flags to blocking const MODE_MASK: u32 = 0b11; + const MODE_NON_BLOCKING_TRIM: u32 = 0b01; const MODE_BLOCK_IF_FULL: u32 = 0b10; - let modified_channel_flags = (channel_flags[0] & !MODE_MASK) | MODE_BLOCK_IF_FULL; + let modified_channel_flags = (channel_flags[0] & !MODE_MASK) + | if is_blocking { + MODE_BLOCK_IF_FULL + } else { + MODE_NON_BLOCKING_TRIM + }; // write flags back core.write_word_32(rtt_buffer_address.into(), modified_channel_flags)?; - // clear the breakpoint we set before - core.clear_hw_breakpoint(main_fn_address.into())?; - Ok(()) } @@ -256,7 +295,7 @@ fn print_logs( let mut logging_channel = if let Some(address) = elf.rtt_buffer_address() { Some(setup_logging_channel(core, memory_map, address)?) } else { - eprintln!("RTT logs not available; blocking until the device halts.."); + eprintln!("RTT logs not available; blocking until the device halts..."); None }; @@ -264,9 +303,10 @@ fn print_logs( .as_ref() .map_or(false, |channel| channel.name() == Some("defmt")); - if use_defmt && opts.no_flash { + if use_defmt && (!opts.reset || opts.no_flash) { log::warn!( - "You are using `--no-flash` and `defmt` logging -- this combination can lead to malformed defmt data!" + "You are using `{}` and `defmt` logging -- this combination can lead to malformed defmt data!", + if !opts.reset { "--no-reset" } else { "--no-flash" } ); } else if use_defmt && elf.defmt_table.is_none() { bail!("\"defmt\" RTT channel is in use, but the firmware binary contains no defmt data"); From c86726421cca38322479e4d4d9c3d5c434654419 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 22 Jun 2023 17:28:59 +0000 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Johann Hemmann --- src/backtrace/unwind.rs | 12 +++----- src/cli.rs | 6 ++-- src/main.rs | 63 ++++++++++++++++++----------------------- 3 files changed, 35 insertions(+), 46 deletions(-) diff --git a/src/backtrace/unwind.rs b/src/backtrace/unwind.rs index 4382d69..34edbbe 100644 --- a/src/backtrace/unwind.rs +++ b/src/backtrace/unwind.rs @@ -105,11 +105,8 @@ pub fn target(core: &mut Core, elf: &Elf, target_info: &TargetInfo) -> Output { output.corrupted = !(reset_fn_range.contains(&pc) || reset_fn_range.is_empty()); if output.corrupted { log::debug!( - "Frame (PC {:#010x}) is not within reset vector ({:#010x}..{:#010x}) \ - and links to itself, the stack is corrupted", - pc, - reset_fn_range.start, - reset_fn_range.end + "Frame (PC {pc:#010x}) is not within reset vector ({reset_fn_range:#010x?}) \ + and links to itself, the stack is corrupted", ); } break; @@ -156,9 +153,8 @@ pub fn target(core: &mut Core, elf: &Elf, target_info: &TargetInfo) -> Output { match registers.get(registers::SP) { Ok(advanced_sp) if advanced_sp > target_info.stack_start => { log::debug!( - "SP ({:#010x}) above start of the stack ({:#010x}), the stack \ - is corrupted", - advanced_sp, + "SP ({advanced_sp:#010x}) above start of the stack ({:#010x}), \ + the stack is corrupted", target_info.stack_start ); output.corrupted = true; diff --git a/src/cli.rs b/src/cli.rs index 71d358b..f6c557b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -60,7 +60,7 @@ pub struct Opts { list_probes: bool, /// Whether to measure the program's stack consumption. - #[arg(long, conflicts_with = "no-reset")] + #[arg(long)] pub measure_stack: bool, /// Skip writing the application binary to flash. @@ -76,8 +76,8 @@ pub struct Opts { pub probe: Option, /// Whether to reset the target when attaching and detaching. Implies `--no-flash`. - #[arg(long = "no-reset", default_value = "true", action = ArgAction::SetFalse)] - pub reset: bool, + #[arg(long)] + pub no_reset: bool, /// Whether to shorten paths (e.g. to crates.io dependencies) in backtraces and defmt logs #[arg(long)] diff --git a/src/main.rs b/src/main.rs index 128ba29..25d78ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,32 +59,27 @@ fn run_target_program(elf_path: &Path, chip_name: &str, opts: &cli::Opts) -> any // reset if requested, and then halt the core; this is necessary for analyzing // the vector table and painting the stack - if opts.reset { - core.reset_and_halt(TIMEOUT)?; - } else { - core.halt(TIMEOUT)?; - } + match opts.no_reset { + false => core.reset_and_halt(TIMEOUT), + true => core.halt(TIMEOUT), + }?; // gather information let elf_bytes = fs::read(elf_path)?; let elf = &Elf::parse(&elf_bytes, elf_path)?; let target_info = TargetInfo::new(elf, memory_map, probe_target)?; - let canary; - if opts.reset { - // install stack canary - canary = Canary::install(core, &target_info, elf, opts.measure_stack)?; - if opts.measure_stack && canary.is_none() { - bail!("failed to set up stack measurement"); - } - } else { - // cannot safely touch the stack of a running application - canary = None; - log::warn!("You are using `--no-reset` -- stack overflow checks will not be done") + // install stack canary + let canary = match opts.no_reset { + true => None, // cannot safely touch the stack of a running application + false => Canary::install(core, &target_info, elf, true)?, + }; + if canary.is_none() { + log::info!("stack measurement was not set up"); } // run program and print logs until there is an exception - attach_to_program(core, elf)?; + attack_the_program(core, elf)?; let current_dir = &env::current_dir()?; let halted_due_to_signal = print_logs(core, current_dir, elf, &target_info.memory_map, opts)?; // blocks until exception print_separator()?; @@ -100,7 +95,7 @@ fn run_target_program(elf_path: &Path, chip_name: &str, opts: &cli::Opts) -> any backtrace::Settings::new(canary_touched, current_dir, halted_due_to_signal, opts); let outcome = backtrace::print(core, elf, &target_info, &mut backtrace_settings)?; - if opts.reset { + if !opts.no_reset { // reset the target core.reset_and_halt(TIMEOUT)?; } else { @@ -214,7 +209,7 @@ fn flashing_progress() -> flashing::FlashProgress { }) } -fn attach_to_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { +fn attack_the_program(core: &mut Core, elf: &Elf) -> anyhow::Result<()> { log::debug!("attaching to program"); match (core.available_breakpoint_units()?, elf.rtt_buffer_address()) { @@ -250,14 +245,12 @@ fn set_rtt_blocking_mode( rtt_buffer_address: u32, is_blocking: bool, ) -> anyhow::Result<()> { - log::debug!( - "setting RTT mode to {}", - if is_blocking { - "blocking" - } else { - "nonblocking" - } - ); + let (mode_name, mode) = match is_blocking { + true => ("blocking", MODE_BLOCK_IF_FULL), + false => ("nonblocking", MODE_NON_BLOCKING_TRIM), + }; + + log::debug!("setting RTT mode to {mode_name}"); // calculate address of up-channel-flags inside the rtt control block const OFFSET: u32 = 44; @@ -270,12 +263,7 @@ fn set_rtt_blocking_mode( const MODE_MASK: u32 = 0b11; const MODE_NON_BLOCKING_TRIM: u32 = 0b01; const MODE_BLOCK_IF_FULL: u32 = 0b10; - let modified_channel_flags = (channel_flags[0] & !MODE_MASK) - | if is_blocking { - MODE_BLOCK_IF_FULL - } else { - MODE_NON_BLOCKING_TRIM - }; + let modified_channel_flags = (channel_flags[0] & !MODE_MASK) | mode; // write flags back core.write_word_32(rtt_buffer_address.into(), modified_channel_flags)?; @@ -305,8 +293,13 @@ fn print_logs( if use_defmt && (!opts.reset || opts.no_flash) { log::warn!( - "You are using `{}` and `defmt` logging -- this combination can lead to malformed defmt data!", - if !opts.reset { "--no-reset" } else { "--no-flash" } + "You are using `{}` together with `defmt` logging -- this combination can lead to malformed defmt data!", + match (opts.no_flash, opts.no_reset) { + (true, true) => "--no-flash and --no-reset", + (true, false) => "--no-flash", + (false, true) => "--no-reset", + (false, false) => unreachable!(), + } ); } else if use_defmt && elf.defmt_table.is_none() { bail!("\"defmt\" RTT channel is in use, but the firmware binary contains no defmt data"); From 5b423b1702540cb19ae2cb89acc082607e159a13 Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Tue, 18 Jul 2023 13:05:27 +0200 Subject: [PATCH 6/6] Fix main.rs --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index db35160..7833cbb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,7 +81,7 @@ fn run_target_program(elf_path: &Path, chip_name: &str, opts: &cli::Opts) -> any // run program and print logs until there is an exception attack_the_program(core, elf)?; let current_dir = env::current_dir()?; - let halted_due_to_signal = print_logs(core, current_dir, elf, &target_info.memory_map, opts)?; // blocks until exception + let halted_due_to_signal = print_logs(core, ¤t_dir, elf, &target_info.memory_map, opts)?; // blocks until exception print_separator()?; // analyze stack canary