substrate/symbol/
memmap.rs

1use crate::error::{Result, SubstrateError};
2use std::collections::HashMap;
3use std::fs::File;
4use std::io::{BufRead, BufReader};
5
6pub struct MemoryMap {
7    pub name: String,
8    pub start: usize,
9    pub end: usize,
10}
11
12pub fn load_memory_maps(pid: libc::pid_t) -> Result<Vec<MemoryMap>> {
13    let path = format!("/proc/{}/maps", pid);
14    let file = File::open(&path).map_err(|e| {
15        SubstrateError::Io(e)
16    })?;
17
18    let reader = BufReader::new(file);
19    let mut maps = Vec::new();
20    let mut map_dict: HashMap<String, (usize, usize)> = HashMap::new();
21
22    for line in reader.lines() {
23        let line = line?;
24        let parts: Vec<&str> = line.split_whitespace().collect();
25
26        if parts.len() < 1 {
27            continue;
28        }
29
30        let addr_parts: Vec<&str> = parts[0].split('-').collect();
31        if addr_parts.len() != 2 {
32            continue;
33        }
34
35        let start = usize::from_str_radix(addr_parts[0], 16)
36            .map_err(|_| SubstrateError::ElfParsing("Invalid address".to_string()))?;
37        let end = usize::from_str_radix(addr_parts[1], 16)
38            .map_err(|_| SubstrateError::ElfParsing("Invalid address".to_string()))?;
39
40        let name = if parts.len() >= 6 {
41            parts[5].to_string()
42        } else {
43            "[memory]".to_string()
44        };
45
46        if let Some((existing_start, existing_end)) = map_dict.get_mut(&name) {
47            if start < *existing_start {
48                *existing_start = start;
49            }
50            if end > *existing_end {
51                *existing_end = end;
52            }
53        } else {
54            map_dict.insert(name.clone(), (start, end));
55        }
56    }
57
58    for (name, (start, end)) in map_dict {
59        maps.push(MemoryMap { name, start, end });
60    }
61
62    Ok(maps)
63}
64
65pub fn find_library_base(pid: libc::pid_t, lib_name: &str) -> Result<usize> {
66    let maps = load_memory_maps(pid)?;
67
68    for map in maps {
69        if map.name == "[memory]" {
70            continue;
71        }
72
73        if let Some(pos) = map.name.rfind('/') {
74            let basename = &map.name[pos + 1..];
75            if basename.starts_with(lib_name) && (basename.len() == lib_name.len() + 3 && basename.ends_with(".so") || basename.len() > lib_name.len() + 3) {
76                unsafe {
77                    libc::mprotect(
78                        map.start as *mut libc::c_void,
79                        map.end - map.start,
80                        libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC,
81                    );
82                }
83                return Ok(map.start);
84            }
85        }
86    }
87
88    Err(SubstrateError::LibraryNotFound(lib_name.to_string()))
89}