1mod annotate;
19mod asm;
20mod header;
21mod layout;
22#[rustfmt::skip] mod ops;
24
25use crate::{Module, Result, bitstream, error, psv, rdat};
26
27pub fn disassemble(container: &[u8]) -> Result<String> {
29 Ok(listing(container)?.text)
30}
31
32#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct Positioned {
36 pub text: String,
38 pub instructions: Vec<Listed>,
42 pub part: [u8; 4],
45 pub bitcode: usize,
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub struct Listed {
54 pub line: usize,
57 pub at: usize,
60 pub end: usize,
62}
63
64pub fn disassemble_with_positions(container: &[u8]) -> Result<Positioned> {
66 let l = listing(container)?;
67 let mut records = Vec::new();
69 for b in &l.blocks {
70 function_records(b, &mut records);
71 }
72 records.sort_unstable();
73 let mut instructions = Vec::with_capacity(l.marks.len());
74 let (mut line, mut counted) = (0usize, 0usize);
75 for mark in &l.marks {
76 let before = l
77 .text
78 .get(counted..mark.byte)
79 .ok_or_else(|| error(mark.at, "an instruction's text"))?;
80 line = line.saturating_add(before.bytes().filter(|&c| c == b'\n').count());
81 counted = mark.byte;
82 let end = records
83 .binary_search_by_key(&mark.at, |&(at, _)| at)
84 .ok()
85 .and_then(|i| records.get(i))
86 .map(|&(_, end)| end)
87 .ok_or_else(|| error(mark.at, "an instruction that is not a record of a function block"))?;
88 instructions.push(Listed {
89 line,
90 at: mark.at,
91 end,
92 });
93 }
94 Ok(Positioned {
95 text: l.text,
96 instructions,
97 part: l.part,
98 bitcode: l.bitcode,
99 })
100}
101
102fn function_records(block: &bitstream::Block, out: &mut Vec<(usize, usize)>) {
104 if block.id == 12 {
106 out.extend(block.records().map(|r| (r.at, r.end)));
107 }
108 for b in block.blocks() {
109 function_records(b, out);
110 }
111}
112
113struct Listing {
115 text: String,
116 marks: Vec<asm::Mark>,
118 blocks: Vec<bitstream::Block>,
120 part: [u8; 4],
121 bitcode: usize,
122}
123
124fn listing(container: &[u8]) -> Result<Listing> {
125 let parts = crate::parts(container)?;
126 let find = |kind: &[u8; 4]| parts.iter().find(|c| &c.kind == kind).map(|c| c.data);
127 let mut s = String::new();
128 if let Some(sfi0) = find(b"SFI0") {
129 header::feature_info(&mut s, sfi0)?;
130 }
131 for (kind, name, input) in [
132 (b"ISG1", "Input", true),
133 (b"OSG1", "Output", false),
134 (b"PSG1", "Patch Constant", false),
135 ] {
136 if let Some(part) = find(kind) {
137 header::part_signature(&mut s, name, part, input)?;
138 }
139 }
140 if let Some(ildn) = find(b"ILDN") {
141 header::debug_name(&mut s, ildn);
142 }
143 if let Some(hash) = find(b"HASH") {
144 header::hash(&mut s, hash)?;
145 }
146 let (part, program) = [*b"ILDB", *b"DXIL"]
148 .into_iter()
149 .find_map(|kind| find(&kind).map(|data| (kind, data)))
150 .ok_or_else(|| error(0, "the container has no DXIL part"))?;
151 let program = crate::program(program)?;
152 let bitcode = program
154 .bitcode
155 .as_ptr()
156 .addr()
157 .checked_sub(container.as_ptr().addr())
158 .filter(|&b| b < container.len())
159 .ok_or_else(|| error(0, "the program's bitcode outside the container"))?;
160 if let Some(part) = find(b"PSV0") {
161 let kind = u8::try_from(program.program_version >> 16 & 0xFF).unwrap_or(u8::MAX);
163 header::psv_runtime(&mut s, &psv::read(part)?, kind)?;
164 }
165 let blocks = bitstream::read(program.bitcode, *b"BC\xc0\xde")?;
166 let module = Module::read(&blocks)?;
167 let reflection = match find(b"STAT").map(crate::program) {
170 Some(Ok(part)) => Some(read(part.bitcode)?),
171 _ => None,
172 };
173 if module.named_metadata.iter().any(|(n, _)| n == "dx.version") {
174 let kind = crate::reflection::shader_model(&module)?
175 .map(|(k, _, _)| k)
176 .ok_or_else(|| error(module.at, "the module has no dx.shaderModel metadata"))?;
177 if kind != "lib" {
178 header::dxil_signatures(&mut s, &module, &kind)?;
179 }
180 header::reflection_sections(&mut s, reflection.as_ref().unwrap_or(&module))?;
181 let subobjects = match find(b"RDAT") {
182 Some(part) => rdat::subobjects(part)?,
183 None => Vec::new(),
184 };
185 if subobjects.is_empty() && module.named_metadata.iter().any(|(n, _)| n == "dx.subobjects") {
186 return Err(error(
187 module.at,
188 "subobjects in dx.subobjects metadata are not supported",
189 ));
190 }
191 header::subobjects(&mut s, &subobjects);
192 }
193 let marks = asm::write(&mut s, &module)?;
194 s.push('\n');
196 Ok(Listing {
197 text: s,
198 marks,
199 blocks,
200 part,
201 bitcode,
202 })
203}
204
205pub fn module_text(m: &Module) -> Result<String> {
207 let mut s = String::new();
208 asm::write(&mut s, m)?;
209 Ok(s)
210}
211
212fn read(bitcode: &[u8]) -> Result<Module> {
213 Module::read(&crate::bitstream::read(bitcode, *b"BC\xc0\xde")?)
214}