summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minidump-writer/src/mac/streams/thread_names.rs
blob: 42242a6397f2d575b44df7d60519ba7270c67ea6 (plain)
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
use super::*;

impl MinidumpWriter {
    /// Writes the [`MDStreamType::ThreadNamesStream`] which is an array of
    /// [`miniduimp_common::format::MINIDUMP_THREAD`]
    pub(crate) fn write_thread_names(
        &mut self,
        buffer: &mut DumpBuf,
        dumper: &TaskDumper,
    ) -> Result<MDRawDirectory, WriterError> {
        let threads = self.threads(dumper);

        let list_header = MemoryWriter::<u32>::alloc_with_val(buffer, threads.len() as u32)?;

        let mut dirent = MDRawDirectory {
            stream_type: MDStreamType::ThreadNamesStream as u32,
            location: list_header.location(),
        };

        let mut names = MemoryArrayWriter::<MDRawThreadName>::alloc_array(buffer, threads.len())?;
        dirent.location.data_size += names.location().data_size;

        for (i, tid) in threads.enumerate() {
            // It's unfortunate if we can't grab a thread name, but it's also
            // not a critical failure
            let name_loc = match Self::write_thread_name(buffer, dumper, tid) {
                Ok(loc) => loc,
                Err(_err) => {
                    // TODO: log error
                    write_string_to_location(buffer, "")?
                }
            };

            let thread = MDRawThreadName {
                thread_id: tid,
                thread_name_rva: name_loc.rva.into(),
            };

            names.set_value_at(buffer, thread, i)?;
        }

        Ok(dirent)
    }

    /// Attempts to retrieve and write the threadname, returning the threa names
    /// location if successful
    fn write_thread_name(
        buffer: &mut Buffer,
        dumper: &TaskDumper,
        tid: u32,
    ) -> Result<MDLocationDescriptor, WriterError> {
        // As noted in usr/include/mach/thread_info.h, the THREAD_EXTENDED_INFO
        // return is exactly the same as proc_pidinfo(..., proc_threadinfo)
        impl mach::ThreadInfo for libc::proc_threadinfo {
            const FLAVOR: u32 = 5; // THREAD_EXTENDED_INFO
        }

        let thread_info: libc::proc_threadinfo = dumper.thread_info(tid)?;

        let name = std::str::from_utf8(
            // SAFETY: This is an initialized block of static size
            unsafe {
                std::slice::from_raw_parts(
                    thread_info.pth_name.as_ptr().cast(),
                    thread_info.pth_name.len(),
                )
            },
        )
        .unwrap_or_default();

        // Ignore the null terminator
        let tname = match name.find('\0') {
            Some(i) => &name[..i],
            None => name,
        };

        Ok(write_string_to_location(buffer, tname)?)
    }
}