1use crate::error::Result;
2use crate::symbol::SymbolTable;
3use memmap2::Mmap;
4use object::{Architecture, BinaryFormat, Object, ObjectSection, SectionKind};
5use std::fs::File;
6use std::path::{Path, PathBuf};
7use std::sync::Arc;
8
9const IN_MEMORY_PATH: &str = "<in-memory>";
11
12pub struct SectionInfo {
13 pub name: String,
14 pub kind: SectionKind,
15 pub address: u64,
16 pub file_range: Option<(u64, u64)>,
17}
18
19pub trait BinaryProvider: Send + Sync {
20 fn format(&self) -> BinaryFormat;
21 fn architecture(&self) -> Architecture;
22 fn section_data(&self, name: &str) -> Option<(&[u8], u64, SectionKind)>;
24 fn symbol_table(&self) -> &SymbolTable;
25 fn path(&self) -> &Path;
26 fn sections(&self) -> &[SectionInfo];
27 fn visit_sections(&self, visitor: &mut dyn FnMut(&str, SectionKind, u64, &[u8]) -> Result<()>) -> Result<()>;
29}
30
31struct ParsedSection {
32 name: String,
33 kind: SectionKind,
34 address: u64,
35 offset: usize,
36 size: usize,
37}
38
39pub struct MmapBinaryProvider {
40 path: PathBuf,
41 mmap: Arc<Mmap>,
42 sections: Vec<ParsedSection>,
43 symbols: SymbolTable,
44 format: BinaryFormat,
45 arch: Architecture,
46 section_infos: Vec<SectionInfo>,
47}
48
49impl MmapBinaryProvider {
50 pub fn open(path: &Path) -> Result<Self> {
52 let file = File::open(path)?;
53 let mmap = unsafe { Mmap::map(&file)? };
54 Self::from_mmap(mmap, path.to_owned())
55 }
56
57 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
60 let mut mmap = memmap2::MmapMut::map_anon(bytes.len().max(1))?;
62 mmap[..bytes.len()].copy_from_slice(bytes);
63 let mmap = mmap.make_read_only()?;
64 Self::from_mmap(mmap, PathBuf::from(IN_MEMORY_PATH))
65 }
66
67 fn from_mmap(mmap: Mmap, path: PathBuf) -> Result<Self> {
68 let obj = object::File::parse(&*mmap)?;
69
70 let format = obj.format();
71 let arch = obj.architecture();
72 let symbols = SymbolTable::build(&obj)?;
73
74 let mut sections = Vec::new();
75 let mut section_infos = Vec::new();
76
77 for section in obj.sections() {
78 let name = section.name().unwrap_or("").to_owned();
79 let kind = section.kind();
80 let address = section.address();
81 let file_range = section.file_range();
82
83 let (offset, size) = match file_range {
84 Some((off, sz)) => (off as usize, sz as usize),
85 None => {
86 section_infos.push(SectionInfo {
87 name: name.clone(),
88 kind,
89 address,
90 file_range: None,
91 });
92 sections.push(ParsedSection {
93 name,
94 kind,
95 address,
96 offset: 0,
97 size: 0,
98 });
99 continue;
100 }
101 };
102
103 section_infos.push(SectionInfo {
104 name: name.clone(),
105 kind,
106 address,
107 file_range: Some((offset as u64, size as u64)),
108 });
109 sections.push(ParsedSection {
110 name,
111 kind,
112 address,
113 offset,
114 size,
115 });
116 }
117
118 Ok(Self {
119 path,
120 mmap: Arc::new(mmap),
121 sections,
122 symbols,
123 format,
124 arch,
125 section_infos,
126 })
127 }
128}
129
130impl BinaryProvider for MmapBinaryProvider {
131 fn format(&self) -> BinaryFormat {
132 self.format
133 }
134
135 fn architecture(&self) -> Architecture {
136 self.arch
137 }
138
139 fn section_data(&self, name: &str) -> Option<(&[u8], u64, SectionKind)> {
140 self.sections.iter().find(|s| s.name == name).and_then(|s| {
141 if s.size == 0 {
142 return None;
143 }
144 let end = s.offset + s.size;
145 if end > self.mmap.len() {
146 return None;
147 }
148 Some((&self.mmap[s.offset..end], s.address, s.kind))
149 })
150 }
151
152 fn visit_sections(&self, visitor: &mut dyn FnMut(&str, SectionKind, u64, &[u8]) -> Result<()>) -> Result<()> {
153 for s in &self.sections {
154 if s.size == 0 {
155 continue;
156 }
157 let end = s.offset + s.size;
158 if end > self.mmap.len() {
159 continue;
160 }
161 visitor(&s.name, s.kind, s.address, &self.mmap[s.offset..end])?;
162 }
163 Ok(())
164 }
165
166 fn symbol_table(&self) -> &SymbolTable {
167 &self.symbols
168 }
169
170 fn path(&self) -> &Path {
171 &self.path
172 }
173
174 fn sections(&self) -> &[SectionInfo] {
175 &self.section_infos
176 }
177}