Skip to main content

dxil_reader/disasm/
mod.rs

1//! A disassembler of DXIL programs: the listing `dxc -dumpbin` (dxc 1.9.2609) prints of a container, byte for byte.
2//!
3//! The listing is dxc's comment header (`dxcdisassembler.cpp`: the feature flags, the signature parts, the debug name
4//! and hash, the pipeline state validation runtime info, and from the program's metadata its signatures, buffer
5//! layouts, resource bindings, view-id state and a library's subobjects), then the program's module as LLVM 3.7 prints
6//! it, with dxc's comment after each call of a DXIL operation. What the reader can't read is an error, never a listing
7//! that differs from dxc's.
8//!
9//! ```no_run
10//! # fn main() -> Result<(), dxil_reader::Error> {
11//! let container = std::fs::read("shader.dxil").expect("a compiled shader");
12//! print!("{}", dxil_reader::disasm::disassemble(&container)?);
13//! # Ok(()) }
14//! ```
15mod annotate;
16mod asm;
17mod header;
18mod layout;
19#[rustfmt::skip] // written by `cargo xtask dxil-ops`, as it is
20mod ops;
21
22use crate::{Module, Result, error, psv, rdat};
23
24/// The listing `dxc -dumpbin` prints of a DXBC container holding a DXIL program, to the newline it ends with.
25pub fn disassemble(container: &[u8]) -> Result<String> {
26    let parts = crate::parts(container)?;
27    let find = |kind: &[u8; 4]| parts.iter().find(|c| &c.kind == kind).map(|c| c.data);
28    let mut s = String::new();
29    if let Some(sfi0) = find(b"SFI0") {
30        header::feature_info(&mut s, sfi0)?;
31    }
32    for (kind, name, input) in [
33        (b"ISG1", "Input", true),
34        (b"OSG1", "Output", false),
35        (b"PSG1", "Patch Constant", false),
36    ] {
37        if let Some(part) = find(kind) {
38            header::part_signature(&mut s, name, part, input)?;
39        }
40    }
41    if let Some(ildn) = find(b"ILDN") {
42        header::debug_name(&mut s, ildn);
43    }
44    if let Some(hash) = find(b"HASH") {
45        header::hash(&mut s, hash)?;
46    }
47    // the debug module, where the container has one, is the one listed
48    let program = find(b"ILDB")
49        .or_else(|| find(b"DXIL"))
50        .ok_or_else(|| error(0, "the container has no DXIL part"))?;
51    let program = crate::program(program)?;
52    if let Some(part) = find(b"PSV0") {
53        header::psv_runtime(&mut s, &psv::read(part)?)?;
54    }
55    let module = read(program.bitcode)?;
56    // the STAT part's module holds the reflection the program part's may be stripped of; dxc ignores one whose header
57    // it can't read
58    let reflection = match find(b"STAT").map(crate::program) {
59        Some(Ok(part)) => Some(read(part.bitcode)?),
60        _ => None,
61    };
62    if module.named_metadata.iter().any(|(n, _)| n == "dx.version") {
63        let kind = crate::reflection::shader_model(&module)?
64            .map(|(k, _, _)| k)
65            .ok_or_else(|| error(module.at, "the module has no dx.shaderModel metadata"))?;
66        if kind != "lib" {
67            header::dxil_signatures(&mut s, &module, &kind)?;
68        }
69        header::reflection_sections(&mut s, reflection.as_ref().unwrap_or(&module))?;
70        let subobjects = match find(b"RDAT") {
71            Some(part) => rdat::subobjects(part)?,
72            None => Vec::new(),
73        };
74        if subobjects.is_empty() && module.named_metadata.iter().any(|(n, _)| n == "dx.subobjects") {
75            return Err(error(
76                module.at,
77                "subobjects in dx.subobjects metadata are not supported",
78            ));
79        }
80        header::subobjects(&mut s, &subobjects);
81    }
82    asm::write(&mut s, &module)?;
83    // dxc's console writer ends the text with a newline of its own
84    s.push('\n');
85    Ok(s)
86}
87
88/// The module part of the listing: from `target datalayout` on, the program's IR as dxc prints it.
89pub fn module_text(m: &Module) -> Result<String> {
90    let mut s = String::new();
91    asm::write(&mut s, m)?;
92    Ok(s)
93}
94
95fn read(bitcode: &[u8]) -> Result<Module> {
96    Module::read(&crate::bitstream::read(bitcode, *b"BC\xc0\xde")?)
97}