1#![deny(missing_docs)]
4#![deny(missing_debug_implementations)]
5
6use std::ffi::OsStr;
7use std::fs;
8use std::io::Read;
9use std::path;
10
11use twiggy_ir as ir;
12use twiggy_traits as traits;
13
14#[cfg(feature = "dwarf")]
15mod object_parse;
16mod wasm_parse;
17
18const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6D];
19
20pub fn read_and_parse<P: AsRef<path::Path>>(
22 path: P,
23 mode: traits::ParseMode,
24) -> anyhow::Result<ir::Items> {
25 let path = path.as_ref();
26 let mut file = fs::File::open(path)?;
27 let mut data = vec![];
28 file.read_to_end(&mut data)?;
29
30 match mode {
31 traits::ParseMode::Wasm => parse_wasm(&data),
32 #[cfg(feature = "dwarf")]
33 traits::ParseMode::Dwarf => parse_other(&data),
34 traits::ParseMode::Auto => parse_auto(path.extension(), &data),
35 }
36}
37
38pub fn parse(data: &[u8]) -> anyhow::Result<ir::Items> {
40 parse_fallback(data)
41}
42
43pub(crate) trait Parse<'a> {
45 type ItemsExtra;
47
48 fn parse_items(
50 self,
51 items: &mut ir::ItemsBuilder,
52 extra: Self::ItemsExtra,
53 ) -> anyhow::Result<()>;
54
55 type EdgesExtra;
57
58 fn parse_edges(
61 self,
62 items: &mut ir::ItemsBuilder,
63 extra: Self::EdgesExtra,
64 ) -> anyhow::Result<()>;
65}
66
67fn parse_auto(extension: Option<&OsStr>, data: &[u8]) -> anyhow::Result<ir::Items> {
68 if sniff_wasm(extension, &data) {
69 parse_wasm(&data)
70 } else {
71 #[cfg(feature = "dwarf")]
72 let res = parse_other(&data);
73 #[cfg(not(feature = "dwarf"))]
74 let res = parse_fallback(&data);
75 res
76 }
77}
78
79fn sniff_wasm(extension: Option<&OsStr>, data: &[u8]) -> bool {
80 match extension.and_then(|s| s.to_str()) {
81 Some("wasm") => true,
82 _ => data.get(0..4) == Some(&WASM_MAGIC_NUMBER),
83 }
84}
85
86fn parse_wasm(data: &[u8]) -> anyhow::Result<ir::Items> {
87 let mut items = ir::ItemsBuilder::new(data.len() as u32);
88
89 let module1 = wasm_parse::ModuleReader::new(data);
90 module1.parse_items(&mut items, ())?;
91 let module2 = wasm_parse::ModuleReader::new(data);
92 module2.parse_edges(&mut items, ())?;
93
94 Ok(items.finish())
95}
96
97#[cfg(feature = "dwarf")]
98fn parse_other(data: &[u8]) -> anyhow::Result<ir::Items> {
99 object_parse::parse(&data)
100}
101
102fn parse_fallback(data: &[u8]) -> anyhow::Result<ir::Items> {
103 parse_wasm(data)
104}