Skip to content
This repository has been archived by the owner on Sep 10, 2024. It is now read-only.

Commit

Permalink
Merge pull request #20 from esp-rs/symbolication-colors
Browse files Browse the repository at this point in the history
Print symbol information with color
  • Loading branch information
kelnos authored Nov 4, 2021
2 parents 267258d + 2425e3d commit bb73bae
Showing 1 changed file with 29 additions and 44 deletions.
73 changes: 29 additions & 44 deletions espmonitor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

use addr2line::Context;
use crossterm::{
QueueableCommand,
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
style::{Color, Print, PrintStyledContent, Stylize},
terminal::{disable_raw_mode, enable_raw_mode},
};
use gimli::{read::Reader, EndianRcSlice, RunTimeEndian};
Expand All @@ -27,7 +29,7 @@ use regex::Regex;
use serial::{self, BaudRate, SerialPort, SystemPort};
use std::{
fs,
io::{self, ErrorKind, Read, Write},
io::{self, ErrorKind, Read, Write, stdout},
process::exit,
time::{Duration, Instant},
};
Expand All @@ -44,8 +46,6 @@ lazy_static! {
.expect("Failed to parse line separator regex");
static ref FUNC_ADDR_RE: Regex = Regex::new(r"0x4[0-9a-f]{7}")
.expect("Failed to parse program address regex");
static ref ADDR2LINE_RE: Regex = Regex::new(r"^0x[0-9a-f]+:\s+([^ ]+)\s+at\s+(\?\?|[0-9]+):(\?|[0-9]+)")
.expect("Failed to parse addr2line output regex");
}

macro_rules! rprintln {
Expand Down Expand Up @@ -148,10 +148,11 @@ fn run_child(args: AppArgs) -> Result<(), Box<dyn std::error::Error>> {
symbols,
};

let mut output = stdout();
let mut buf = [0u8; 1024];
loop {
match dev.read(&mut buf) {
Ok(bytes) if bytes > 0 => handle_serial(&mut serial_state, &buf[0..bytes])?,
Ok(bytes) if bytes > 0 => handle_serial(&mut serial_state, &buf[0..bytes], &mut output)?,
Ok(_) => if dev.read_dsr().is_err() {
rprintln!("Device disconnected; exiting");
break Ok(());
Expand Down Expand Up @@ -190,7 +191,7 @@ fn reset_chip(dev: &mut SystemPort) -> io::Result<()> {
Ok(())
}

fn handle_serial(state: &mut SerialState, buf: &[u8]) -> io::Result<()> {
fn handle_serial(state: &mut SerialState, buf: &[u8], output: &mut dyn Write) -> io::Result<()> {
let data = String::from_utf8_lossy(buf);
let mut lines = LINE_SEP_RE.split(&data).collect::<Vec<&str>>();

Expand All @@ -211,8 +212,7 @@ fn handle_serial(state: &mut SerialState, buf: &[u8]) -> io::Result<()> {
};

if !full_line.is_empty() {
let processed_line = process_line(state, full_line);
rprintln!("{}", processed_line);
output_line(state, full_line, output)?;
state.unfinished_line.clear();
}
}
Expand All @@ -221,38 +221,49 @@ fn handle_serial(state: &mut SerialState, buf: &[u8]) -> io::Result<()> {
state.unfinished_line.push_str(nel);
state.last_unfinished_line_at = Instant::now();
} else if !state.unfinished_line.is_empty() && state.last_unfinished_line_at.elapsed() > UNFINISHED_LINE_TIMEOUT {
let processed_line = process_line(state, &state.unfinished_line);
rprintln!("{}", processed_line);
output_line(state, &state.unfinished_line, output)?;
state.unfinished_line.clear();
}

Ok(())
}

fn process_line(state: &SerialState, line: &str) -> String {
let mut updated_line = line.to_string();

fn output_line(state: &SerialState, line: &str, output: &mut dyn Write) -> io::Result<()> {
if let Some(symbols) = state.symbols.as_ref() {
let mut cur_start_offset = 0;

for mat in FUNC_ADDR_RE.find_iter(line) {
let (function, file, line) = u64::from_str_radix(&mat.as_str()[2..], 16)
let (function, file, lineno) = u64::from_str_radix(&mat.as_str()[2..], 16)
.ok()
.map(|addr| {
let function = find_function_name(symbols, addr);
let (file, line) = find_location(symbols, addr);
(function, file, line)
let (file, lineno) = find_location(symbols, addr);
(function, file, lineno)
})
.unwrap_or((None, None, None));

fn or_qq(s: Option<String>) -> String {
s.unwrap_or_else(|| "??".to_string())
}

let name = format!("{} [{}:{}:{}]", mat.as_str(), or_qq(function), or_qq(file), or_qq(line.map(|l| l.to_string())));
updated_line = updated_line.replace(mat.as_str(), &name);
output.queue(Print(line[cur_start_offset..mat.end()].to_string()))?;
cur_start_offset = mat.end();
let symbolicated_name = format!(" [{}:{}:{}]", or_qq(function), or_qq(file), or_qq(lineno.map(|l| l.to_string())))
.with(Color::Yellow);
output.queue(PrintStyledContent(symbolicated_name))?;
}

if cur_start_offset < line.len() {
output.queue(Print(line[cur_start_offset..line.len()].to_string()))?;
}
} else {
output.queue(Print(line.to_string()))?;
}

updated_line
output.write_all(b"\r\n")?;
output.flush()?;

Ok(())
}

fn handle_input(dev: &mut SystemPort, key_event: KeyEvent) -> io::Result<()> {
Expand Down Expand Up @@ -286,29 +297,3 @@ fn find_location(symbols: &Symbols<'_>, addr: u64) -> (Option<String>, Option<u3
))
.unwrap_or((None, None))
}

//fn find_frame(context: &Context<EndianRcSlice<RunTimeEndian>>, addr: u64) -> Result<Option<(Option<String>, Option<String>, Option<u32>)>, String> {
// context
// .find_frames(addr)
// .and_then(|mut frames| frames.next())
// .map_err(|err| err.to_string())
// .map(|frame| frame.map(|frame|
// (
// frame.function.and_then(|fname| fname.name.to_string_lossy().ok().map(|name| name.into_owned())),
// frame.location.as_ref().and_then(|location| location.file).map(|file| file.to_string()),
// frame.location.as_ref().and_then(|location| location.line)
// )
// ))
//}
//
//fn find_symbol_and_loc<'a, O: Object<'a, 'a> + 'a>(obj: O, context: &Context<EndianRcSlice<RunTimeEndian>>, addr: u64) -> Result<Option<(Option<String>, Option<String>, Option<u32>)>, String> {
// let symbols = obj.symbol_map();
// let fname = symbols.get(addr).map(|sym| sym.name().to_string());
//
// let location = context.find_location(addr)
// .map_err(|err| err.to_string())?;
// let file = location.as_ref().and_then(|location| location.file).map(|file| file.to_string());
// let line = location.as_ref().and_then(|location| location.line);
//
// Ok(fname.map(|fname| (Some(fname), file, line)))
//}

0 comments on commit bb73bae

Please sign in to comment.