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 { let threads = self.threads(dumper); let list_header = MemoryWriter::::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::::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) => { log::warn!("failed to write thread name for thread {tid}: {err}"); 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 { // 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)?) } }