target_gen/
algorithm_binary.rs1use goblin::{
2 elf::program_header::PT_LOAD,
3 elf64::section_header::{SHT_NOBITS, SHT_PROGBITS},
4};
5use probe_rs_target::MemoryRange;
6
7use anyhow::{Result, anyhow};
8
9const CODE_SECTION_KEY: (&str, u32) = ("PrgCode", SHT_PROGBITS);
10const DATA_SECTION_KEY: (&str, u32) = ("PrgData", SHT_PROGBITS);
11const BSS_SECTION_KEY: (&str, u32) = ("PrgData", SHT_NOBITS);
12
13const SUSPICIOUS_SECTION_NAMES: &[&str] = &[".text", ".rodata", ".data", ".sdata", ".bss", ".sbss"];
20
21#[derive(Debug, Clone)]
23pub(crate) struct Section {
24 pub(crate) start: u32,
25 pub(crate) length: u32,
26 pub(crate) data: Vec<u8>,
27
28 pub(crate) load_address: u32,
32}
33
34#[derive(Debug, Clone)]
36pub(crate) struct AlgorithmBinary {
37 pub(crate) code_section: Section,
38 pub(crate) data_section: Section,
39 pub(crate) bss_section: Section,
40}
41
42impl AlgorithmBinary {
43 pub(crate) fn new(elf: &goblin::elf::Elf<'_>, buffer: &[u8]) -> Result<Self> {
45 let mut code_section = None;
46 let mut data_section = None;
47 let mut bss_section = None;
48
49 let mut suspicious_sections = Vec::new();
50
51 for ph in &elf.program_headers {
53 if ph.p_type == PT_LOAD && ph.p_memsz > 0 {
56 let sector = ph.p_offset..ph.p_offset + ph.p_memsz;
57
58 log::debug!("Program header: LOAD to VMA {:#010x}", ph.p_vaddr);
59
60 for sh in &elf.section_headers {
62 let range = sh.sh_offset..sh.sh_offset + sh.sh_size;
63 if sector.contains_range(&range) {
64 let data = if sh.sh_type == SHT_NOBITS {
66 Vec::new()
67 } else {
68 Vec::from(&buffer[sh.sh_offset as usize..][..sh.sh_size as usize])
69 };
70
71 let section = Some(Section {
72 start: sh.sh_addr as u32,
73 length: sh.sh_size as u32,
74 data,
75 load_address: (ph.p_vaddr + sh.sh_offset - ph.p_offset) as u32,
76 });
77
78 match (&elf.shdr_strtab[sh.sh_name], sh.sh_type) {
80 CODE_SECTION_KEY => code_section = section,
81 DATA_SECTION_KEY => data_section = section,
82 BSS_SECTION_KEY => bss_section = section,
83 (name, _section_type) => {
84 if SUSPICIOUS_SECTION_NAMES.contains(&name) {
85 suspicious_sections.push(name);
86 }
87 }
88 }
89 }
90 }
91 }
92 }
93
94 if !suspicious_sections.is_empty() {
95 log::warn!(
96 "The ELF file contains some unexpected sections, which should not be part of a flash loader: "
97 );
98
99 for section in suspicious_sections {
100 log::warn!("\t{section}");
101 }
102
103 log::warn!(
104 "Code should be placed in the '{}' section, and data should be placed in the '{}' section.",
105 CODE_SECTION_KEY.0,
106 DATA_SECTION_KEY.0
107 );
108 }
109
110 let code_section = code_section.ok_or_else(|| {
112 anyhow!(
113 "Section '{}' not found, which is required to be present.",
114 CODE_SECTION_KEY.0
115 )
116 })?;
117
118 let data_section = data_section.unwrap_or_else(|| Section {
119 start: code_section.start + code_section.length,
120 length: 0,
121 data: Vec::new(),
122 load_address: code_section.load_address + code_section.length,
123 });
124
125 let zi_start = data_section.start + data_section.length;
126 let zi_address = data_section.load_address + data_section.length;
127
128 Ok(Self {
129 code_section,
130 data_section,
131 bss_section: bss_section.unwrap_or_else(|| Section {
132 start: zi_start,
133 length: 0,
134 data: Vec::new(),
135 load_address: zi_address,
136 }),
137 })
138 }
139
140 pub(crate) fn blob(&self) -> Vec<u8> {
142 let mut blob = Vec::new();
143
144 blob.extend(&self.code_section.data);
145 blob.extend(&self.data_section.data);
146 blob.extend(&vec![0; self.bss_section.length as usize]);
147
148 blob
149 }
150
151 pub(crate) fn is_continuous_in_ram(&self) -> bool {
158 (self.code_section.load_address + self.code_section.length
159 == self.data_section.load_address)
160 && (self.data_section.load_address + self.data_section.length
161 == self.bss_section.load_address)
162 }
163}