Skip to main content

flowey_lib_hvlite/
run_split_debug_info.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Splits debug info from a binary into a separate file using `objcopy`
5
6use crate::common::CommonArch;
7use flowey::node::prelude::*;
8
9flowey_request! {
10    pub struct Request {
11        pub arch: CommonArch,
12        pub in_bin: ReadVar<PathBuf>,
13        pub out_bin: WriteVar<PathBuf>,
14        pub out_dbg_info: WriteVar<PathBuf>,
15        // TODO: This is only necessary because our .dbg file is not reproducible and the build-id
16        // is a hash over the binary + the .dbg file, rendering the whole build non-reproducible.
17        // We don't want to do this for all builds because we would lose the ability for the debugger
18        // to auto-discover the .dbg file when debugging. For now, this is only used for Nix builds
19        // where reproducibility is the main concern and will be removed when the debug file is reproducible.
20        /// When true, remove `.note.gnu.build-id` and omit `--add-gnu-debuglink`
21        /// to produce byte-for-byte reproducible stripped binaries.
22        pub reproducible_without_debuglink: bool,
23    }
24}
25
26new_simple_flow_node!(struct Node);
27
28impl SimpleFlowNode for Node {
29    type Request = Request;
30
31    fn imports(ctx: &mut ImportCtx<'_>) {
32        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
33    }
34
35    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
36        let Request {
37            arch,
38            in_bin,
39            out_bin,
40            out_dbg_info,
41            reproducible_without_debuglink,
42        } = request;
43
44        let host_arch = ctx.arch();
45        let platform = ctx.platform();
46
47        let (objcopy_pkg, objcopy_bin): (Option<&str>, &str) = match arch {
48            CommonArch::X86_64 => match platform {
49                FlowPlatform::Linux(linux_distribution) => match linux_distribution {
50                    FlowPlatformLinuxDistro::Fedora => (
51                        Some("binutils-x86_64-linux-gnu"),
52                        "x86_64-linux-gnu-objcopy",
53                    ),
54                    FlowPlatformLinuxDistro::Ubuntu => (
55                        Some("binutils-x86-64-linux-gnu"),
56                        "x86_64-linux-gnu-objcopy",
57                    ),
58                    FlowPlatformLinuxDistro::AzureLinux => {
59                        match_arch!(host_arch, FlowArch::X86_64, (Some("binutils"), "objcopy"))
60                    }
61                    FlowPlatformLinuxDistro::Arch | FlowPlatformLinuxDistro::OpenSuse => {
62                        match_arch!(host_arch, FlowArch::X86_64, (Some("binutils"), "objcopy"))
63                    }
64                    FlowPlatformLinuxDistro::Nix => (None, "x86_64-linux-gnu-objcopy"),
65                    FlowPlatformLinuxDistro::Unknown => anyhow::bail!("Unknown Linux distribution"),
66                },
67                _ => anyhow::bail!("Unsupported platform"),
68            },
69            CommonArch::Aarch64 => match platform {
70                FlowPlatform::Linux(linux_distribution) => match linux_distribution {
71                    FlowPlatformLinuxDistro::Fedora | FlowPlatformLinuxDistro::Ubuntu => (
72                        Some("binutils-aarch64-linux-gnu"),
73                        "aarch64-linux-gnu-objcopy",
74                    ),
75                    FlowPlatformLinuxDistro::AzureLinux => match host_arch {
76                        FlowArch::Aarch64 => (Some("binutils"), "objcopy"),
77                        FlowArch::X86_64 => (
78                            Some("binutils-aarch64-linux-gnu"),
79                            "aarch64-linux-gnu-objcopy",
80                        ),
81                        _ => anyhow::bail!("unsupported host arch {host_arch:?}"),
82                    },
83                    FlowPlatformLinuxDistro::Arch => {
84                        match_arch!(
85                            host_arch,
86                            FlowArch::X86_64,
87                            (
88                                Some("aarch64-linux-gnu-binutils"),
89                                "aarch64-linux-gnu-objcopy"
90                            )
91                        )
92                    }
93                    FlowPlatformLinuxDistro::OpenSuse => {
94                        match_arch!(host_arch, FlowArch::Aarch64, (Some("binutils"), "objcopy"))
95                    }
96                    FlowPlatformLinuxDistro::Nix => (None, "aarch64-linux-gnu-objcopy"),
97                    FlowPlatformLinuxDistro::Unknown => {
98                        anyhow::bail!("Unknown Linux distribution")
99                    }
100                },
101                _ => anyhow::bail!("Unsupported platform"),
102            },
103        };
104
105        let installed_objcopy = objcopy_pkg.map(|objcopy_pkg| {
106            ctx.reqv(
107                |side_effect| flowey_lib_common::install_dist_pkg::Request::Install {
108                    package_names: vec![objcopy_pkg.into()],
109                    done: side_effect,
110                },
111            )
112        });
113
114        ctx.emit_rust_step("split debug symbols", |ctx| {
115            installed_objcopy.claim(ctx);
116            let in_bin = in_bin.claim(ctx);
117            let out_bin = out_bin.claim(ctx);
118            let out_dbg_info = out_dbg_info.claim(ctx);
119            move |rt| {
120                let in_bin = rt.read(in_bin);
121
122                let output = rt.sh.current_dir().join(in_bin.file_name().unwrap());
123                flowey::shell_cmd!(rt, "{objcopy_bin} --only-keep-debug {in_bin} {output}.dbg")
124                    .run()?;
125                if reproducible_without_debuglink {
126                    flowey::shell_cmd!(
127                        rt,
128                        "{objcopy_bin} --strip-all --keep-section=.build_info --remove-section=.note.gnu.build-id {in_bin} {output}"
129                    )
130                    .run()?;
131                } else {
132                    flowey::shell_cmd!(
133                        rt,
134                        "{objcopy_bin} --strip-all --keep-section=.build_info --add-gnu-debuglink={output}.dbg {in_bin} {output}"
135                    )
136                    .run()?;
137                }
138
139                let output = output.absolute()?;
140
141                rt.write(out_bin, &output);
142                rt.write(out_dbg_info, &output.with_extension("dbg"));
143
144                Ok(())
145            }
146        });
147
148        Ok(())
149    }
150}