Skip to content

Commit bc656c7

Browse files
authored
pulley: Add a simple disassembler example (#9656)
Should be useful when inspecting `*.cwasm` files since the system-default `objdump` doesn't work.
1 parent 5ed60c2 commit bc656c7

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pulley/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ sptr = { workspace = true }
2020

2121
[dev-dependencies]
2222
env_logger = { workspace = true }
23+
object = { workspace = true, features = ['std'] }
24+
anyhow = { workspace = true, features = ['std'] }
2325

2426
[features]
2527
std = []
@@ -31,3 +33,7 @@ interp = ["decode", "encode"]
3133

3234
[package.metadata.docs.rs]
3335
all-features = true
36+
37+
[[example]]
38+
name = "objdump"
39+
required-features = ["disas"]

pulley/examples/objdump.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//! Small helper utility to disassemble `*.cwasm` files produced by Wasmtime.
2+
//!
3+
//! Run with:
4+
//!
5+
//! cargo run --example objdump -F disas -p pulley-interpreter foo.cwasm
6+
7+
use anyhow::{bail, Result};
8+
use object::{File, Object as _, ObjectSection, ObjectSymbol, SectionKind, SymbolKind};
9+
use pulley_interpreter::decode::Decoder;
10+
use pulley_interpreter::disas::Disassembler;
11+
12+
fn main() -> Result<()> {
13+
let cwasm = std::fs::read(std::env::args().nth(1).unwrap())?;
14+
15+
let image = File::parse(&cwasm[..])?;
16+
17+
let text = match image.sections().find(|s| s.kind() == SectionKind::Text) {
18+
Some(section) => section.data()?,
19+
None => bail!("no text section"),
20+
};
21+
22+
for sym in image.symbols() {
23+
if !sym.is_definition() {
24+
continue;
25+
}
26+
if sym.kind() != SymbolKind::Text {
27+
continue;
28+
}
29+
let address = sym.address();
30+
let size = sym.size();
31+
if size == 0 {
32+
continue;
33+
}
34+
35+
let name = sym.name()?;
36+
let code = &text[address as usize..][..size as usize];
37+
38+
println!("{address:#08x}: <{name}>:");
39+
let mut disas = Disassembler::new(code);
40+
disas.start_offset(address as usize);
41+
let result = Decoder::decode_all(&mut disas);
42+
println!("{}", disas.disas());
43+
if let Err(e) = result {
44+
println!(" : error disassembling: {e:?}");
45+
}
46+
}
47+
Ok(())
48+
}

pulley/src/disas.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub struct Disassembler<'a> {
1717
raw_bytecode: &'a [u8],
1818
bytecode: SafeBytecodeStream<'a>,
1919
disas: String,
20+
start_offset: usize,
2021
start: usize,
2122
temp: String,
2223
offsets: bool,
@@ -39,6 +40,7 @@ impl<'a> Disassembler<'a> {
3940
bytecode: SafeBytecodeStream::new(bytecode),
4041
disas: String::new(),
4142
start: 0,
43+
start_offset: 0,
4244
temp: String::new(),
4345
offsets: true,
4446
hexdump: true,
@@ -61,6 +63,16 @@ impl<'a> Disassembler<'a> {
6163
self
6264
}
6365

66+
/// Configures the offset that this function starts from, if it doesn't
67+
/// start from 0.
68+
///
69+
/// This can possibly be useful when a single function at a time is being
70+
/// disassembled.
71+
pub fn start_offset(&mut self, offset: usize) -> &mut Self {
72+
self.start_offset = offset;
73+
self
74+
}
75+
6476
/// Get the disassembly thus far.
6577
pub fn disas(&self) -> &str {
6678
&self.disas
@@ -73,7 +85,7 @@ impl<'a> Disassembler<'a> {
7385
write!(&mut self.temp, ",").unwrap();
7486
}
7587
write!(&mut self.temp, " ").unwrap();
76-
val.disas(self.start, &mut self.temp);
88+
val.disas(self.start + self.start_offset, &mut self.temp);
7789
}
7890
}
7991
}
@@ -216,7 +228,7 @@ impl<'a> OpVisitor for Disassembler<'a> {
216228

217229
fn after_visit(&mut self) {
218230
if self.offsets {
219-
write!(&mut self.disas, "{:8x}: ", self.start).unwrap();
231+
write!(&mut self.disas, "{:8x}: ", self.start + self.start_offset).unwrap();
220232
}
221233
if self.hexdump {
222234
let size = self.bytecode.position() - self.start;

0 commit comments

Comments
 (0)