1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use diagnostics_data::{DiagnosticsHierarchy, InspectData};

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CoredumpReport {
    pub idx: usize,
    pub thread_koid: u64,
    pub process_koid: u64,
    pub pid: i64,
    pub argv: String,
}

impl CoredumpReport {
    /// Returns `None` if the snapshot seems partially-written, indicating a retry is warranted.
    ///
    /// # Panics
    ///
    /// If the snapshot has the same rough structure as Starnix's inspect output but was incorrectly
    /// recorded.
    pub fn extract_from_snapshot(data: &InspectData) -> Option<Vec<Self>> {
        let DiagnosticsHierarchy { name, properties, children, .. } = data
            .payload
            .as_ref()?
            .get_child_by_path(&["container", "kernel", "coredumps"])
            .cloned()?;
        assert_eq!(name, "coredumps");
        assert_eq!(properties, vec![]);

        // Examine all of the properties and children so that we are alerted that this test code may
        // need to be updated if coredump reports gain new information.
        let mut reports = vec![];
        for DiagnosticsHierarchy {
            name: idx_str,
            properties: coredump_properties,
            children: coredump_children,
            ..
        } in children
        {
            assert!(
                coredump_children.is_empty(),
                "coredump reports aren't expected to have children, found {coredump_children:?}"
            );

            let mut argv = None;
            let mut process_koid = None;
            let mut thread_koid = None;
            let mut pid = None;
            for property in coredump_properties {
                match property.name() {
                    "argv" => {
                        argv = Some(
                            property
                                .string()
                                .expect("getting argv string from report node")
                                .to_string(),
                        )
                    }
                    "thread_koid" => {
                        thread_koid =
                            Some(property.uint().expect("getting thread koid from report node"))
                    }
                    "process_koid" => {
                        process_koid =
                            Some(property.uint().expect("getting process koid from report node"))
                    }

                    // TODO(https://fxbug.dev/42081072) i64/int in kernel shows up as u64/uint here
                    "pid" => {
                        pid = Some(property.uint().expect("getting pid from report node") as i64)
                    }
                    other => panic!("unrecognized coredump report property `{other}`"),
                }
            }

            reports.push(Self {
                idx: idx_str.parse().expect("starnix coredump node names should be integers"),
                thread_koid: thread_koid.expect("retrieving thread koid property"),
                process_koid: process_koid.expect("retrieving process koid property"),
                pid: pid.expect("retrieving pid property"),
                argv: argv.expect("retrieving argv property"),
            });
        }
        reports.sort();

        Some(reports)
    }
}