Skip to content

Commit fa9e9d8

Browse files
committed
debugger: support OsString #15
1 parent 19b5a04 commit fa9e9d8

File tree

3 files changed

+118
-10
lines changed

3 files changed

+118
-10
lines changed

debugger/testcases/os_string.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use std::path::PathBuf;
2+
3+
fn func(v: &PathBuf) {
4+
println!("{v:?}");
5+
}
6+
7+
fn main() {
8+
let mut path = PathBuf::new();
9+
path.push(r"/");
10+
path.push("home");
11+
path.push("hello");
12+
func(&path);
13+
}

debugger/tests/os_string.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
mod util;
2+
use util::*;
3+
4+
use anyhow::Result;
5+
use firedbg_rust_debugger::{Bytes, Debugger, Event, EventStream};
6+
use pretty_assertions::assert_eq;
7+
use sea_streamer::{Buffer, Consumer, Message, Producer};
8+
9+
#[tokio::test]
10+
async fn main() -> Result<()> {
11+
let testcase = "os_string";
12+
let (producer, consumer) = setup(testcase).await?;
13+
14+
let debugger_params = debugger_params_from_file(testcase);
15+
Debugger::run(debugger_params, producer.clone());
16+
17+
producer.end().await?;
18+
19+
for i in 0..4 {
20+
let payload = consumer.next().await?.message().into_bytes();
21+
let event = EventStream::read_from(Bytes::from(payload));
22+
println!("#{i} {:?}", event);
23+
24+
match event {
25+
Event::Breakpoint { .. } => unreachable!(),
26+
Event::FunctionCall { arguments, .. } => {
27+
if i == 1 {
28+
let string = arguments[0].1.to_string();
29+
assert_eq!(
30+
string,
31+
r#"&std::path::PathBuf { inner: std::ffi::os_str::OsString::from_encoded_bytes_unchecked(String::from("/home/hello").into_bytes()) }"#
32+
);
33+
}
34+
}
35+
Event::FunctionReturn { .. } => {}
36+
}
37+
}
38+
39+
Ok(())
40+
}

protocol/src/value.rs

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub const STD_HASH_STATE: &str = ", std::collections::hash::map::RandomState>";
1414
pub const CORE_REF_CELL: &str = "core::cell::RefCell<";
1515
pub const STD_MUTEX: &str = "std::sync::mutex::Mutex<";
1616
pub const STD_RWLOCK: &str = "std::sync::rwlock::RwLock<";
17+
pub const STD_OS_STRING: &str = "std::ffi::os_str::OsString";
1718

1819
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1920
#[serde(tag = "type")]
@@ -297,15 +298,7 @@ impl Display for RValue {
297298
if typename.starts_with('&') {
298299
write!(f, "&")?;
299300
}
300-
write!(f, "[")?;
301-
for (i, b) in value.iter().enumerate() {
302-
write!(
303-
f,
304-
"0x{b:02x}{}",
305-
if i < value.len() - 1 { ", " } else { "" }
306-
)?;
307-
}
308-
write!(f, "]")?;
301+
print_bytes(f, &value)?;
309302
}
310303
Self::Ref {
311304
typename, value, ..
@@ -409,7 +402,9 @@ impl Display for RValue {
409402
}
410403
return write!(f, ")");
411404
}
412-
if (typename.starts_with(STD_HASH_MAP) || typename.starts_with(STD_HASH_SET))
405+
if typename == STD_OS_STRING {
406+
print_os_string(f, fields, width, pretty)?;
407+
} else if (typename.starts_with(STD_HASH_MAP) || typename.starts_with(STD_HASH_SET))
413408
&& typename.ends_with(STD_HASH_STATE)
414409
&& (fields.contains_key("items") && fields.contains_key("len"))
415410
{
@@ -652,6 +647,53 @@ fn print_hashmap(
652647
Ok(())
653648
}
654649

650+
fn print_os_string(
651+
f: &mut std::fmt::Formatter<'_>,
652+
fields: &IndexMap<String, RValue>,
653+
width: usize,
654+
pretty: bool,
655+
) -> std::fmt::Result {
656+
write!(f, "{}::from_encoded_bytes_unchecked(", STD_OS_STRING)?;
657+
if pretty {
658+
write!(
659+
f,
660+
"{}",
661+
String::from_utf8(vec![b' '; (width + 1) * 4]).unwrap()
662+
)?;
663+
}
664+
let inner = match fields.get("inner") {
665+
Some(RValue::Struct { fields, .. }) => {
666+
if let Some(inner) = fields.get("inner") {
667+
match inner {
668+
RValue::Bytes { value, .. } => value,
669+
_ => {
670+
write!(f, "?)")?;
671+
return Ok(());
672+
}
673+
}
674+
} else {
675+
write!(f, "?)")?;
676+
return Ok(());
677+
}
678+
}
679+
_ => {
680+
write!(f, "?)")?;
681+
return Ok(());
682+
}
683+
};
684+
if let Ok(string) = std::str::from_utf8(inner) {
685+
write!(f, "String::from({:?}).into_bytes()", string)?;
686+
} else {
687+
write!(f, "vec!")?;
688+
print_bytes(f, inner)?;
689+
}
690+
if pretty {
691+
write!(f, "{}", String::from_utf8(vec![b' '; width * 4]).unwrap())?;
692+
}
693+
write!(f, ")")?;
694+
Ok(())
695+
}
696+
655697
fn print_arr_items(
656698
f: &mut std::fmt::Formatter<'_>,
657699
data: &[RValue],
@@ -683,6 +725,19 @@ fn print_arr_items(
683725
Ok(())
684726
}
685727

728+
fn print_bytes(f: &mut std::fmt::Formatter<'_>, bytes: &[u8]) -> std::fmt::Result {
729+
write!(f, "[")?;
730+
for (i, b) in bytes.iter().enumerate() {
731+
write!(
732+
f,
733+
"0x{b:02x}{}",
734+
if i < bytes.len() - 1 { ", " } else { "" }
735+
)?;
736+
}
737+
write!(f, "]")?;
738+
Ok(())
739+
}
740+
686741
impl RValue {
687742
pub fn typename(&self) -> String {
688743
match self {

0 commit comments

Comments
 (0)