1 use crate::errors::SectionMappingsError;
2 use crate::linux_ptrace_dumper::LinuxPtraceDumper;
3 use crate::maps_reader::MappingInfo;
4 use crate::minidump_format::*;
5 use crate::minidump_writer::{DumpBuf, MinidumpWriter};
6 use crate::sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter};
7
8 type Result<T> = std::result::Result<T, SectionMappingsError>;
9
10 /// Write information about the mappings in effect. Because we are using the
11 /// minidump format, the information about the mappings is pretty limited.
12 /// Because of this, we also include the full, unparsed, /proc/$x/maps file in
13 /// another stream in the file.
write( config: &mut MinidumpWriter, buffer: &mut DumpBuf, dumper: &mut LinuxPtraceDumper, ) -> Result<MDRawDirectory>14 pub fn write(
15 config: &mut MinidumpWriter,
16 buffer: &mut DumpBuf,
17 dumper: &mut LinuxPtraceDumper,
18 ) -> Result<MDRawDirectory> {
19 let mut modules = Vec::new();
20
21 // First write all the mappings from the dumper
22 for map_idx in 0..dumper.mappings.len() {
23 // If the mapping is uninteresting, or if
24 // there is caller-provided information about this mapping
25 // in the user_mapping_list list, skip it
26
27 if !dumper.mappings[map_idx].is_interesting()
28 || dumper.mappings[map_idx].is_contained_in(&config.user_mapping_list)
29 {
30 continue;
31 }
32 // Note: elf_identifier_for_mapping_index() can manipulate the |mapping.name|.
33 let identifier = dumper
34 .elf_identifier_for_mapping_index(map_idx)
35 .unwrap_or_default();
36
37 // If the identifier is all 0, its an uninteresting mapping (bmc#1676109)
38 if identifier.is_empty() || identifier.iter().all(|&x| x == 0) {
39 continue;
40 }
41
42 let module = fill_raw_module(buffer, &dumper.mappings[map_idx], &identifier)?;
43 modules.push(module);
44 }
45
46 // Next write all the mappings provided by the caller
47 for user in &config.user_mapping_list {
48 // GUID was provided by caller.
49 let module = fill_raw_module(buffer, &user.mapping, &user.identifier)?;
50 modules.push(module)
51 }
52
53 let list_header = MemoryWriter::<u32>::alloc_with_val(buffer, modules.len() as u32)?;
54
55 let mut dirent = MDRawDirectory {
56 stream_type: MDStreamType::ModuleListStream as u32,
57 location: list_header.location(),
58 };
59
60 if !modules.is_empty() {
61 let mapping_list = MemoryArrayWriter::<MDRawModule>::alloc_from_array(buffer, &modules)?;
62 dirent.location.data_size += mapping_list.location().data_size;
63 }
64
65 Ok(dirent)
66 }
67
fill_raw_module( buffer: &mut DumpBuf, mapping: &MappingInfo, identifier: &[u8], ) -> Result<MDRawModule>68 fn fill_raw_module(
69 buffer: &mut DumpBuf,
70 mapping: &MappingInfo,
71 identifier: &[u8],
72 ) -> Result<MDRawModule> {
73 let cv_record: MDLocationDescriptor;
74 if identifier.is_empty() {
75 // Just zeroes
76 cv_record = Default::default();
77 } else {
78 let cv_signature = MD_CVINFOELF_SIGNATURE;
79 let array_size = std::mem::size_of_val(&cv_signature) + identifier.len();
80
81 let mut sig_section = MemoryArrayWriter::<u8>::alloc_array(buffer, array_size)?;
82 for (index, val) in cv_signature
83 .to_ne_bytes()
84 .iter()
85 .chain(identifier.iter())
86 .enumerate()
87 {
88 sig_section.set_value_at(buffer, *val, index)?;
89 }
90 cv_record = sig_section.location();
91 }
92
93 let (file_path, _) = mapping
94 .get_mapping_effective_name_and_path()
95 .map_err(|e| SectionMappingsError::GetEffectivePathError(mapping.clone(), e))?;
96 let name_header = write_string_to_location(buffer, &file_path)?;
97
98 Ok(MDRawModule {
99 base_of_image: mapping.start_address as u64,
100 size_of_image: mapping.size as u32,
101 cv_record,
102 module_name_rva: name_header.rva,
103 ..Default::default()
104 })
105 }
106