Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- A new CLI argument `rom-elf` was added which will be used for backtraces (#963)

### Changed

### Fixed
Expand Down
4 changes: 3 additions & 1 deletion cargo-espflash/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,11 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {

monitor_args.elf = Some(build_ctx.artifact_path);

let elfs = vec![elf_data.as_ref()];

monitor(
flasher.into(),
Some(&elf_data),
elfs,
pid,
monitor_args,
args.connect_args.non_interactive,
Expand Down
Binary file added espflash/resources/roms/esp32_rev0_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32_rev300_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32c2_rev100_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32c3_rev0_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32c3_rev101_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32c3_rev3_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32c6_rev0_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32h2_rev0_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32p4_rev0_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32s2_rev0_rom.elf
Binary file not shown.
Binary file added espflash/resources/roms/esp32s3_rev0_rom.elf
Binary file not shown.
16 changes: 14 additions & 2 deletions espflash/src/bin/espflash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
check_idf_bootloader(&elf_data)?;
}

print_board_info(&mut flasher)?;
let dev_info = print_board_info(&mut flasher)?;
ensure_chip_compatibility(chip, Some(elf_data.as_slice()))?;

let mut flash_config = args.flash_config_args;
Expand Down Expand Up @@ -326,9 +326,21 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {

monitor_args.elf = Some(args.image);

let mut elfs = Vec::new();
elfs.push(elf_data.as_ref());

let rom_elf;
if let Some(rom) = &monitor_args.rom_elf {
rom_elf = std::fs::read(rom).unwrap();
elfs.push(rom_elf.as_ref());
} else if let Some(rom) = dev_info.rom() {
rom_elf = rom;
elfs.push(rom_elf.as_ref())
}

monitor(
flasher.into(),
Some(&elf_data),
elfs,
pid,
monitor_args,
args.connect_args.non_interactive,
Expand Down
34 changes: 27 additions & 7 deletions espflash/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use crate::{
},
error::{Error, MissingPartition, MissingPartitionTable},
flasher::{
DeviceInfo,
FLASH_SECTOR_SIZE,
FlashData,
FlashFrequency,
Expand Down Expand Up @@ -303,6 +304,10 @@ pub struct MonitorConfigArgs {
/// ELF image to load the symbols from
#[arg(long, value_name = "FILE")]
pub elf: Option<PathBuf>,
/// Optional ELF image to load ROM symbols from - if not given espflash will
/// try to use a matching built-in ROM
#[arg(long, value_name = "FILE")]
pub rom_elf: Option<PathBuf>,
/// Avoids restarting the device before monitoring
///
/// Only valid when `non_interactive` is also set.
Expand Down Expand Up @@ -607,7 +612,7 @@ pub fn parse_chip_rev(chip_rev: &str) -> Result<u16> {
}

/// Print information about a chip
pub fn print_board_info(flasher: &mut Flasher) -> Result<()> {
pub fn print_board_info(flasher: &mut Flasher) -> Result<DeviceInfo> {
let info = flasher.device_info()?;
print!("Chip type: {}", info.chip);

Expand All @@ -621,19 +626,19 @@ pub fn print_board_info(flasher: &mut Flasher) -> Result<()> {
println!("Flash size: {}", info.flash_size);
println!("Features: {}", info.features.join(", "));

if let Some(mac) = info.mac_address {
if let Some(ref mac) = info.mac_address {
println!("MAC address: {mac}");
}

Ok(())
Ok(info)
}

/// Open a serial monitor
pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> {
let mut flasher = connect(&args.connect_args, config, true, true)?;
let pid = flasher.connection().usb_pid();

let elf = if let Some(elf_path) = args.monitor_args.elf.clone() {
let firmware_elf = if let Some(elf_path) = args.monitor_args.elf.clone() {
let path = fs::canonicalize(elf_path).into_diagnostic()?;
let data = fs::read(path).into_diagnostic()?;

Expand All @@ -643,8 +648,9 @@ pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> {
};

let chip = flasher.chip();
let dev_info = flasher.device_info()?;

ensure_chip_compatibility(chip, elf.as_deref())?;
ensure_chip_compatibility(chip, firmware_elf.as_deref())?;

let mut monitor_args = args.monitor_args;

Expand All @@ -657,9 +663,23 @@ pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> {
monitor_args.monitor_baud = 74_880;
}

let mut elfs: Vec<&[u8]> = Vec::new();
if let Some(firmware_elf) = firmware_elf.as_ref() {
elfs.push(firmware_elf);
}

let rom_elf;
if let Some(ref rom) = monitor_args.rom_elf {
rom_elf = std::fs::read(rom).unwrap();
elfs.push(rom_elf.as_ref());
} else if let Some(rom) = dev_info.rom() {
rom_elf = rom;
elfs.push(rom_elf.as_ref())
}

monitor(
flasher.into(),
elf.as_deref(),
elfs,
pid,
monitor_args,
args.connect_args.non_interactive,
Expand Down Expand Up @@ -1162,7 +1182,7 @@ pub fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
}
monitor(
flasher.into(),
None,
Vec::new(),
pid,
monitor_args,
args.connect_args.non_interactive,
Expand Down
11 changes: 6 additions & 5 deletions espflash/src/cli/monitor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl Drop for RawModeGuard {
/// parser.
pub fn monitor(
mut serial: Port,
elf: Option<&[u8]>,
elfs: Vec<&[u8]>,
pid: u16,
monitor_args: MonitorConfigArgs,
non_interactive: bool,
Expand All @@ -104,19 +104,20 @@ pub fn monitor(
// We are in raw mode until `_raw_mode` is dropped (ie. this function returns).
let _raw_mode = RawModeGuard::new();

let firmware_elf = elfs.first().map(|v| &**v);
let stdout = stdout();
let mut stdout = if monitor_args.no_addresses {
ResolvingPrinter::new_no_addresses(elf, stdout.lock())
ResolvingPrinter::new_no_addresses(firmware_elf, stdout.lock())
} else {
ResolvingPrinter::new(elf, stdout.lock())
ResolvingPrinter::new(elfs, stdout.lock())
};

let mut parser: Box<dyn InputParser> = match monitor_args
.log_format
.unwrap_or_else(|| deduce_log_format(elf))
.unwrap_or_else(|| deduce_log_format(firmware_elf))
{
LogFormat::Defmt => Box::new(parser::esp_defmt::EspDefmt::new(
elf,
firmware_elf,
monitor_args.output_format,
)?),
LogFormat::Serial => {
Expand Down
42 changes: 21 additions & 21 deletions espflash/src/cli/monitor/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,23 @@ impl Utf8Merger {
#[allow(missing_debug_implementations)]
pub struct ResolvingPrinter<'ctx, W: Write> {
writer: W,
symbols: Option<Symbols<'ctx>>,
elf: Option<&'ctx [u8]>,
symbols: Vec<Symbols<'ctx>>,
elfs: Vec<&'ctx [u8]>,
merger: Utf8Merger,
line_fragment: String,
disable_address_resolution: bool,
}

impl<'ctx, W: Write> ResolvingPrinter<'ctx, W> {
/// Creates a new `ResolvingPrinter` with the given ELF file and writer.
pub fn new(elf: Option<&'ctx [u8]>, writer: W) -> Self {
pub fn new(elf: Vec<&'ctx [u8]>, writer: W) -> Self {
Self {
writer,
symbols: elf.and_then(|elf| Symbols::try_from(elf).ok()),
elf,
symbols: elf
.iter()
.filter_map(|elf| Symbols::try_from(elf).ok())
.collect(),
elfs: elf,
merger: Utf8Merger::new(),
line_fragment: String::new(),
disable_address_resolution: false,
Expand All @@ -132,8 +135,8 @@ impl<'ctx, W: Write> ResolvingPrinter<'ctx, W> {
pub fn new_no_addresses(_elf: Option<&'ctx [u8]>, writer: W) -> Self {
Self {
writer,
symbols: None, // Don't load symbols when address resolution is disabled
elf: None,
symbols: Vec::new(), // Don't load symbols when address resolution is disabled
elfs: Vec::new(),
merger: Utf8Merger::new(),
line_fragment: String::new(),
disable_address_resolution: true,
Expand Down Expand Up @@ -176,24 +179,21 @@ impl<W: Write> Write for ResolvingPrinter<'_, W> {

// If we have loaded some symbols and address resolution is not disabled...
if !self.disable_address_resolution {
if let Some(symbols) = self.symbols.as_ref() {
for symbols in &self.symbols {
// Try to print the names of addresses in the current line.
resolve_addresses(symbols, &line, &mut self.writer)?;
}

if line.starts_with(stack_dump::MARKER) {
if let Some(symbols) = self.symbols.as_ref() {
if stack_dump::backtrace_from_stack_dump(
&line,
&mut self.writer,
self.elf,
symbols,
)
.is_err()
{
self.writer.queue(Print("\nUnable to decode stack-dump. Double check `-Cforce-unwind-tables` is used.\n"))?;
}
}
if line.starts_with(stack_dump::MARKER)
&& stack_dump::backtrace_from_stack_dump(
&line,
&mut self.writer,
&self.elfs,
&self.symbols,
)
.is_err()
{
self.writer.queue(Print("\nUnable to decode stack-dump. Double check `-Cforce-unwind-tables` is used.\n"))?;
}
}
}
Expand Down
105 changes: 53 additions & 52 deletions espflash/src/cli/monitor/stack_dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,52 @@ pub(crate) const MARKER: &str = "STACKDUMP: ";
pub(crate) fn backtrace_from_stack_dump(
line: &str,
out: &mut dyn Write,
elf: Option<&[u8]>,
symbols: &Symbols<'_>,
elfs: &Vec<&[u8]>,
symbols: &Vec<Symbols<'_>>,
) -> std::io::Result<()> {
if let Some(elf) = elf {
if let Some(remaining) = line.to_string().strip_prefix(MARKER) {
let mut split = remaining.split(" ");
let (address, stack) = {
let first = split.next();
let second = split.next();

(first, second)
};

if let Some(address) = address {
if let Some(stack) = stack {
if stack.len() % 2 != 0 {
return Ok(());
}
if let Some(remaining) = line.to_string().strip_prefix(MARKER) {
let mut split = remaining.split(" ");
let (address, stack) = {
let first = split.next();
let second = split.next();

(first, second)
};

if let Some(address) = address {
if let Some(stack) = stack {
if stack.len() % 2 != 0 {
return Ok(());
}

let mut pc = u32::from_str_radix(address, 16).unwrap_or_default();
let mut stack_bytes = Vec::new();
for byte_chars in stack.chars().collect::<Vec<char>>().chunks(2) {
if byte_chars.len() == 2 {
stack_bytes.push(
u8::from_str_radix(
&format!("{}{}", byte_chars[0], byte_chars[1]),
16,
)
let mut pc = u32::from_str_radix(address, 16).unwrap_or_default();
let mut stack_bytes = Vec::new();
for byte_chars in stack.chars().collect::<Vec<char>>().chunks(2) {
if byte_chars.len() == 2 {
stack_bytes.push(
u8::from_str_radix(&format!("{}{}", byte_chars[0], byte_chars[1]), 16)
.unwrap_or_default(),
);
}
);
}
}

let func_info = get_func_info(elf)?;
let mut func_info = Vec::new();
for elf in elfs {
func_info.append(&mut get_func_info(elf)?);
}

writeln!(out).ok();
let mut index = 0;
loop {
let func = func_info.iter().find(|f| f.start <= pc && f.end >= pc);
if let Some(func) = func {
if func.stack_frame_size == 0 {
break;
}
writeln!(out).ok();
let mut index = 0;
loop {
let func = func_info.iter().find(|f| f.start <= pc && f.end >= pc);
if let Some(func) = func {
if func.stack_frame_size == 0 {
break;
}

let lookup_pc = pc as u64 - 4;
let lookup_pc = pc as u64 - 4;

for symbols in symbols {
let name = symbols.name(lookup_pc);
let location = symbols.location(lookup_pc);
if let Some(name) = name {
Expand All @@ -64,25 +65,25 @@ pub(crate) fn backtrace_from_stack_dump(
writeln!(out, "{name}\r\n at ??:??\r\n").ok();
}
}
}

if index + func.stack_frame_size as usize > stack_bytes.len() {
break;
}

let next_pc_pos = index + (func.stack_frame_size as usize - 4);

pc = u32::from_le_bytes(
stack_bytes[next_pc_pos..][..4]
.try_into()
.unwrap_or_default(),
);
index += func.stack_frame_size as usize;
} else {
if index + func.stack_frame_size as usize > stack_bytes.len() {
break;
}

let next_pc_pos = index + (func.stack_frame_size as usize - 4);

pc = u32::from_le_bytes(
stack_bytes[next_pc_pos..][..4]
.try_into()
.unwrap_or_default(),
);
index += func.stack_frame_size as usize;
} else {
break;
}
writeln!(out).ok();
}
writeln!(out).ok();
}
}
}
Expand Down
Loading