summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minidump_writer_linux/src/sections/mappings.rs
blob: 912eb0f3ddcb91b6d00fb76843e65aba5a09550b (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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use crate::linux_ptrace_dumper::LinuxPtraceDumper;
use crate::maps_reader::MappingInfo;
use crate::minidump_format::*;
use crate::minidump_writer::{DumpBuf, MinidumpWriter};
use crate::sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter};
use crate::Result;

/// Write information about the mappings in effect. Because we are using the
/// minidump format, the information about the mappings is pretty limited.
/// Because of this, we also include the full, unparsed, /proc/$x/maps file in
/// another stream in the file.
pub fn write(
    config: &mut MinidumpWriter,
    buffer: &mut DumpBuf,
    dumper: &mut LinuxPtraceDumper,
) -> Result<MDRawDirectory> {
    let mut num_output_mappings = config.user_mapping_list.len();

    for mapping in &dumper.mappings {
        // If the mapping is uninteresting, or if
        // there is caller-provided information about this mapping
        // in the user_mapping_list list, skip it
        if mapping.is_interesting() && !mapping.is_contained_in(&config.user_mapping_list) {
            num_output_mappings += 1;
        }
    }

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

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

    // In case of num_output_mappings == 0, this call doesn't allocate any memory in the buffer
    let mut mapping_list =
        MemoryArrayWriter::<MDRawModule>::alloc_array(buffer, num_output_mappings)?;
    dirent.location.data_size += mapping_list.location().data_size;

    // First write all the mappings from the dumper
    let mut idx = 0;
    for map_idx in 0..dumper.mappings.len() {
        if !dumper.mappings[map_idx].is_interesting()
            || dumper.mappings[map_idx].is_contained_in(&config.user_mapping_list)
        {
            continue;
        }
        // Note: elf_identifier_for_mapping_index() can manipulate the |mapping.name|.
        let identifier = dumper
            .elf_identifier_for_mapping_index(map_idx)
            .unwrap_or(Default::default());
        let module = fill_raw_module(buffer, &dumper.mappings[map_idx], &identifier)?;
        mapping_list.set_value_at(buffer, module, idx)?;
        idx += 1;
    }

    // Next write all the mappings provided by the caller
    for user in &config.user_mapping_list {
        // GUID was provided by caller.
        let module = fill_raw_module(buffer, &user.mapping, &user.identifier)?;
        mapping_list.set_value_at(buffer, module, idx)?;
        idx += 1;
    }
    Ok(dirent)
}

fn fill_raw_module(
    buffer: &mut DumpBuf,
    mapping: &MappingInfo,
    identifier: &[u8],
) -> Result<MDRawModule> {
    let cv_record: MDLocationDescriptor;
    if identifier.is_empty() {
        // Just zeroes
        cv_record = Default::default();
    } else {
        let cv_signature = MD_CVINFOELF_SIGNATURE;
        let array_size = std::mem::size_of_val(&cv_signature) + identifier.len();

        let mut sig_section = MemoryArrayWriter::<u8>::alloc_array(buffer, array_size)?;
        for (index, val) in cv_signature
            .to_ne_bytes()
            .iter()
            .chain(identifier.iter())
            .enumerate()
        {
            sig_section.set_value_at(buffer, *val, index)?;
        }
        cv_record = sig_section.location();
    }

    let (file_path, _) = mapping.get_mapping_effective_name_and_path()?;
    let name_header = write_string_to_location(buffer, &file_path)?;

    Ok(MDRawModule {
        base_of_image: mapping.start_address as u64,
        size_of_image: mapping.size as u32,
        cv_record,
        module_name_rva: name_header.rva,
        ..Default::default()
    })
}