1 use crate::error
::{self, Error}
;
2 use crate::pe
::relocation
;
3 use alloc
::string
::{String, ToString}
;
4 use scroll
::{ctx, Pread, Pwrite}
;
7 #[derive(Debug, PartialEq, Clone, Default)]
8 pub struct SectionTable
{
10 pub real_name
: Option
<String
>,
11 pub virtual_size
: u32,
12 pub virtual_address
: u32,
13 pub size_of_raw_data
: u32,
14 pub pointer_to_raw_data
: u32,
15 pub pointer_to_relocations
: u32,
16 pub pointer_to_linenumbers
: u32,
17 pub number_of_relocations
: u16,
18 pub number_of_linenumbers
: u16,
19 pub characteristics
: u32,
22 pub const SIZEOF_SECTION_TABLE
: usize = 8 * 5;
24 // Based on https://github.com/llvm-mirror/llvm/blob/af7b1832a03ab6486c42a40d21695b2c03b2d8a3/lib/Object/COFFObjectFile.cpp#L70
25 // Decodes a string table entry in base 64 (//AAAAAA). Expects string without
27 fn base64_decode_string_entry(s
: &str) -> Result
<usize, ()> {
28 assert
!(s
.len() <= 6, "String too long, possible overflow.");
32 let v
= if b'A'
<= c
&& c
<= b'Z'
{
35 } else if b'a'
<= c
&& c
<= b'z'
{
38 } else if b'
0'
<= c
&& c
<= b'
9'
{
50 val
= val
* 64 + v
as usize;
59 string_table_offset
: usize,
60 ) -> error
::Result
<Self> {
61 let mut table
= SectionTable
::default();
62 let mut name
= [0u8; 8];
63 name
.copy_from_slice(bytes
.gread_with(offset
, 8)?
);
66 table
.virtual_size
= bytes
.gread_with(offset
, scroll
::LE
)?
;
67 table
.virtual_address
= bytes
.gread_with(offset
, scroll
::LE
)?
;
68 table
.size_of_raw_data
= bytes
.gread_with(offset
, scroll
::LE
)?
;
69 table
.pointer_to_raw_data
= bytes
.gread_with(offset
, scroll
::LE
)?
;
70 table
.pointer_to_relocations
= bytes
.gread_with(offset
, scroll
::LE
)?
;
71 table
.pointer_to_linenumbers
= bytes
.gread_with(offset
, scroll
::LE
)?
;
72 table
.number_of_relocations
= bytes
.gread_with(offset
, scroll
::LE
)?
;
73 table
.number_of_linenumbers
= bytes
.gread_with(offset
, scroll
::LE
)?
;
74 table
.characteristics
= bytes
.gread_with(offset
, scroll
::LE
)?
;
76 if let Some(idx
) = table
.name_offset()?
{
77 table
.real_name
= Some(bytes
.pread
::<&str>(string_table_offset
+ idx
)?
.to_string());
82 pub fn name_offset(&self) -> error
::Result
<Option
<usize>> {
83 // Based on https://github.com/llvm-mirror/llvm/blob/af7b1832a03ab6486c42a40d21695b2c03b2d8a3/lib/Object/COFFObjectFile.cpp#L1054
84 if self.name
[0] == b'
/'
{
85 let idx
: usize = if self.name
[1] == b'
/'
{
86 let b64idx
= self.name
.pread
::<&str>(2)?
;
87 base64_decode_string_entry(b64idx
).map_err(|_
| {
88 Error
::Malformed(format
!(
89 "Invalid indirect section name //{}: base64 decoding failed",
94 let name
= self.name
.pread
::<&str>(1)?
;
95 name
.parse().map_err(|err
| {
96 Error
::Malformed(format
!("Invalid indirect section name /{}: {}", name
, err
))
105 #[allow(clippy::useless_let_if_seq)]
106 pub fn set_name_offset(&mut self, mut idx
: usize) -> error
::Result
<()> {
107 if idx
<= 9_999_999 {
109 // write!(&mut self.name[1..], "{}", idx) without using io::Write.
110 // We write into a temporary since we calculate digits starting at the right.
111 let mut name
= [0; 7];
118 let rem
= (idx
% 10) as u8;
120 name
[6 - len
] = b'
0'
+ rem
;
126 self.name
[1..][..len
].copy_from_slice(&name
[7 - len
..]);
128 } else if idx
as u64 <= 0xfff_fff_fff {
133 let rem
= (idx
% 64) as u8;
136 0..=25 => b'A'
+ rem
,
137 26..=51 => b'a'
+ rem
- 26,
138 52..=61 => b'
0'
+ rem
- 52,
143 self.name
[7 - i
] = c
;
147 Err(Error
::Malformed(format
!(
148 "Invalid section name offset: {}",
154 pub fn name(&self) -> error
::Result
<&str> {
155 match self.real_name
.as_ref() {
157 None
=> Ok(self.name
.pread(0)?
),
161 pub fn relocations
<'a
>(&self, bytes
: &'a
[u8]) -> error
::Result
<relocation
::Relocations
<'a
>> {
162 let offset
= self.pointer_to_relocations
as usize;
163 let number
= self.number_of_relocations
as usize;
164 relocation
::Relocations
::parse(bytes
, offset
, number
)
168 impl ctx
::SizeWith
<scroll
::Endian
> for SectionTable
{
169 fn size_with(_ctx
: &scroll
::Endian
) -> usize {
174 impl ctx
::TryIntoCtx
<scroll
::Endian
> for SectionTable
{
175 type Error
= error
::Error
;
176 fn try_into_ctx(self, bytes
: &mut [u8], ctx
: scroll
::Endian
) -> Result
<usize, Self::Error
> {
178 bytes
.gwrite(&self.name
[..], offset
)?
;
179 bytes
.gwrite_with(self.virtual_size
, offset
, ctx
)?
;
180 bytes
.gwrite_with(self.virtual_address
, offset
, ctx
)?
;
181 bytes
.gwrite_with(self.size_of_raw_data
, offset
, ctx
)?
;
182 bytes
.gwrite_with(self.pointer_to_raw_data
, offset
, ctx
)?
;
183 bytes
.gwrite_with(self.pointer_to_relocations
, offset
, ctx
)?
;
184 bytes
.gwrite_with(self.pointer_to_linenumbers
, offset
, ctx
)?
;
185 bytes
.gwrite_with(self.number_of_relocations
, offset
, ctx
)?
;
186 bytes
.gwrite_with(self.number_of_linenumbers
, offset
, ctx
)?
;
187 bytes
.gwrite_with(self.characteristics
, offset
, ctx
)?
;
188 Ok(SIZEOF_SECTION_TABLE
)
192 impl ctx
::IntoCtx
<scroll
::Endian
> for SectionTable
{
193 fn into_ctx(self, bytes
: &mut [u8], ctx
: scroll
::Endian
) {
194 bytes
.pwrite_with(self, 0, ctx
).unwrap();
198 /// The section should not be padded to the next boundary. This flag is obsolete and is replaced
199 /// by `IMAGE_SCN_ALIGN_1BYTES`. This is valid only for object files.
200 pub const IMAGE_SCN_TYPE_NO_PAD
: u32 = 0x0000_0008;
201 /// The section contains executable code.
202 pub const IMAGE_SCN_CNT_CODE
: u32 = 0x0000_0020;
203 /// The section contains initialized data.
204 pub const IMAGE_SCN_CNT_INITIALIZED_DATA
: u32 = 0x0000_0040;
205 /// The section contains uninitialized data.
206 pub const IMAGE_SCN_CNT_UNINITIALIZED_DATA
: u32 = 0x0000_0080;
207 pub const IMAGE_SCN_LNK_OTHER
: u32 = 0x0000_0100;
208 /// The section contains comments or other information. The .drectve section has this type.
209 /// This is valid for object files only.
210 pub const IMAGE_SCN_LNK_INFO
: u32 = 0x0000_0200;
211 /// The section will not become part of the image. This is valid only for object files.
212 pub const IMAGE_SCN_LNK_REMOVE
: u32 = 0x0000_0800;
213 /// The section contains COMDAT data. This is valid only for object files.
214 pub const IMAGE_SCN_LNK_COMDAT
: u32 = 0x0000_1000;
215 /// The section contains data referenced through the global pointer (GP).
216 pub const IMAGE_SCN_GPREL
: u32 = 0x0000_8000;
217 pub const IMAGE_SCN_MEM_PURGEABLE
: u32 = 0x0002_0000;
218 pub const IMAGE_SCN_MEM_16BIT
: u32 = 0x0002_0000;
219 pub const IMAGE_SCN_MEM_LOCKED
: u32 = 0x0004_0000;
220 pub const IMAGE_SCN_MEM_PRELOAD
: u32 = 0x0008_0000;
222 pub const IMAGE_SCN_ALIGN_1BYTES
: u32 = 0x0010_0000;
223 pub const IMAGE_SCN_ALIGN_2BYTES
: u32 = 0x0020_0000;
224 pub const IMAGE_SCN_ALIGN_4BYTES
: u32 = 0x0030_0000;
225 pub const IMAGE_SCN_ALIGN_8BYTES
: u32 = 0x0040_0000;
226 pub const IMAGE_SCN_ALIGN_16BYTES
: u32 = 0x0050_0000;
227 pub const IMAGE_SCN_ALIGN_32BYTES
: u32 = 0x0060_0000;
228 pub const IMAGE_SCN_ALIGN_64BYTES
: u32 = 0x0070_0000;
229 pub const IMAGE_SCN_ALIGN_128BYTES
: u32 = 0x0080_0000;
230 pub const IMAGE_SCN_ALIGN_256BYTES
: u32 = 0x0090_0000;
231 pub const IMAGE_SCN_ALIGN_512BYTES
: u32 = 0x00A0_0000;
232 pub const IMAGE_SCN_ALIGN_1024BYTES
: u32 = 0x00B0_0000;
233 pub const IMAGE_SCN_ALIGN_2048BYTES
: u32 = 0x00C0_0000;
234 pub const IMAGE_SCN_ALIGN_4096BYTES
: u32 = 0x00D0_0000;
235 pub const IMAGE_SCN_ALIGN_8192BYTES
: u32 = 0x00E0_0000;
236 pub const IMAGE_SCN_ALIGN_MASK
: u32 = 0x00F0_0000;
238 /// The section contains extended relocations.
239 pub const IMAGE_SCN_LNK_NRELOC_OVFL
: u32 = 0x0100_0000;
240 /// The section can be discarded as needed.
241 pub const IMAGE_SCN_MEM_DISCARDABLE
: u32 = 0x0200_0000;
242 /// The section cannot be cached.
243 pub const IMAGE_SCN_MEM_NOT_CACHED
: u32 = 0x0400_0000;
244 /// The section is not pageable.
245 pub const IMAGE_SCN_MEM_NOT_PAGED
: u32 = 0x0800_0000;
246 /// The section can be shared in memory.
247 pub const IMAGE_SCN_MEM_SHARED
: u32 = 0x1000_0000;
248 /// The section can be executed as code.
249 pub const IMAGE_SCN_MEM_EXECUTE
: u32 = 0x2000_0000;
250 /// The section can be read.
251 pub const IMAGE_SCN_MEM_READ
: u32 = 0x4000_0000;
252 /// The section can be written to.
253 pub const IMAGE_SCN_MEM_WRITE
: u32 = 0x8000_0000;
260 fn set_name_offset() {
261 let mut section
= SectionTable
::default();
262 for &(offset
, name
) in [
263 (0usize
, b
"/0\0\0\0\0\0\0"),
264 (1, b
"/1\0\0\0\0\0\0"),
265 (9_999_999, b
"/9999999"),
266 (10_000_000, b
"//AAmJaA"),
267 #[cfg(target_pointer_width = "64")]
268 (0xfff_fff_fff, b
"////////"),
272 section
.set_name_offset(offset
).unwrap();
273 assert_eq
!(§ion
.name
, name
);
274 assert_eq
!(section
.name_offset().unwrap(), Some(offset
));
276 #[cfg(target_pointer_width = "64")]
277 assert
!(section
.set_name_offset(0x1_000_000_000).is_err());